Code

store: Fixed JSON serialization when skipping hosts due to filters.
authorSebastian Harl <sh@tokkee.org>
Tue, 29 Jul 2014 20:49:44 +0000 (22:49 +0200)
committerSebastian Harl <sh@tokkee.org>
Tue, 29 Jul 2014 20:49:44 +0000 (22:49 +0200)
Previously, it might have happened that a comma was appended to a list of
hosts even though all subsequent hosts were filtered out. This created invalid
JSON. Now, don't let sdb_store_host_tojson ignore hosts entirely. Instead,
always let it serialize the host passed to the function and only pass on the
filter to child objects. The caller is now responsible for calling the filter
and, at the same time, the caller is able to correctly handle skipped hosts.

Fixed the unit-test which should have caught this.

src/core/store.c
src/include/core/store.h
t/unit/core/store_test.c

index bb6cb96a45bb4b91d934705324e06b179b4742b4..cc0927e3376a354278abddbcfbd6e064c48c83a3 100644 (file)
@@ -629,9 +629,6 @@ sdb_store_host_tojson(sdb_store_obj_t *h, sdb_strbuf_t *buf,
        if ((! h) || (h->type != SDB_HOST) || (! buf))
                return -1;
 
-       if (filter && (! sdb_store_matcher_matches(filter, h, NULL)))
-               return 0;
-
        sdb_strbuf_append(buf, "{\"name\": \"%s\", ", SDB_OBJ(host)->name);
        store_common_tojson(h, buf);
 
@@ -653,6 +650,7 @@ int
 sdb_store_tojson(sdb_strbuf_t *buf, sdb_store_matcher_t *filter, int flags)
 {
        sdb_avltree_iter_t *host_iter;
+       size_t len;
 
        if (! buf)
                return -1;
@@ -667,20 +665,22 @@ sdb_store_tojson(sdb_strbuf_t *buf, sdb_store_matcher_t *filter, int flags)
 
        sdb_strbuf_append(buf, "{\"hosts\":[");
 
+       len = sdb_strbuf_len(buf);
        while (sdb_avltree_iter_has_next(host_iter)) {
                sdb_store_obj_t *host;
-               size_t len = sdb_strbuf_len(buf);
 
                host = STORE_OBJ(sdb_avltree_iter_get_next(host_iter));
                assert(host);
 
-               if (sdb_store_host_tojson(host, buf, filter, flags))
-                       return -1;
+               if (filter && (! sdb_store_matcher_matches(filter, host, NULL)))
+                       continue;
 
-               /* sdb_store_host_tojson may leave the buffer unmodified */
-               if ((sdb_avltree_iter_has_next(host_iter))
-                               && (sdb_strbuf_len(buf) != len))
+               if (sdb_strbuf_len(buf) > len)
                        sdb_strbuf_append(buf, ",");
+               len = sdb_strbuf_len(buf);
+
+               if (sdb_store_host_tojson(host, buf, filter, flags))
+                       return -1;
        }
 
        sdb_strbuf_append(buf, "]}");
index 494f8d648c241834100c56a29560b6d58fd5ca6f..308523a4476a1b861ad134e43815d7372088b036 100644 (file)
@@ -420,8 +420,9 @@ sdb_store_tojson(sdb_strbuf_t *buf, sdb_store_matcher_t *filter, int flags);
  * Serialize a host object to JSON and append the result to the specified
  * buffer. If specified, only objects matching the filter will be included in
  * the result. The filter is applied to each object individually and, thus,
- * should not be of any object-type specific kind. If the filter rejects the
- * host object, the function returns success but leaves the buffer unmodified.
+ * should not be of any object-type specific kind. The filter is never applied
+ * to the specified host object; the caller is responsible for this and for
+ * correctly handling skipped hosts.
  *
  * Returns:
  *  - 0 on success
index bc2066a208b98afabc1921efb6c8b8dd683370f5..e5383b43c60599c5d5ff8d9316f510081a7802ad 100644 (file)
@@ -450,7 +450,7 @@ START_TEST(test_store_tojson)
                                                        "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
                                                        "\"update_interval\": \"0s\", \"backends\": []},"
                                        "], "
-                                       "\"services\": []},"
+                                       "\"services\": []}"
                        "]}" },
                { { sdb_store_ge_matcher, SDB_FIELD_LAST_UPDATE,
                                { SDB_TYPE_DATETIME, { .datetime = 3 } } }, 0,