Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/store_memcached.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@
memcached_return_t rc;
char * buf_raw;

if (m == NULL) {
snprintf(log_msg, 1024, "Failed to allocate memory for metatile header\n");
return -1;
}

mask = METATILE - 1;
meta_offset = (x & mask) * METATILE + (y & mask);

Expand Down Expand Up @@ -235,7 +240,6 @@
char * buf;
size_t len;
uint32_t flags;
uint64_t cas;
memcached_return_t rc;

//TODO: deal with options
Expand All @@ -246,11 +250,11 @@
return -1;
}

//cas = memcached_result_cas(&rc);

((struct stat_info *)buf)->expired = 1;

rc = memcached_cas(store->storage_ctx, meta_path, strlen(meta_path), buf, len, 0, flags, cas);
// memcached_get() does not return a CAS value, so a compare-and-swap cannot be used here
// (the previous code passed an uninitialised CAS token). Replace the existing item instead.
rc = memcached_replace(store->storage_ctx, meta_path, strlen(meta_path), buf, len, 0, flags);

if (rc != MEMCACHED_SUCCESS) {
free(buf);
Expand Down
12 changes: 11 additions & 1 deletion src/store_rados.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@
int err;
char * buf_raw;

if (m == NULL) {
snprintf(log_msg, 1024, "Failed to allocate memory for metatile header\n");
return -1;
}

mask = METATILE - 1;
meta_offset = (x & mask) * METATILE + (y & mask);

Expand Down Expand Up @@ -234,6 +239,11 @@
char * buf2 = malloc(sz2);
int err;

if (buf2 == NULL) {
g_logger(G_LOG_LEVEL_ERROR, "rados_metatile_write: failed to allocate memory for write buffer");
return -1;
}

tile_stat.expired = 0;
tile_stat.size = sz;
tile_stat.mtime = time(NULL);
Expand Down Expand Up @@ -352,7 +362,7 @@
int err;
int i;

if (ctx == NULL) {
if (ctx == NULL || store == NULL) {
free(ctx);
free(store);
return NULL;
Expand Down
53 changes: 52 additions & 1 deletion src/store_ro_composite.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,12 @@ static int ro_composite_metatile_expire(struct storage_backend * store, const ch
static int ro_composite_close_storage(struct storage_backend * store)
{
struct ro_composite_ctx * ctx = (struct ro_composite_ctx *)(store->storage_ctx);
// close_storage() no longer frees the backend itself (#524), so free the
// two inner backends here, as the callers do for the outer one
ctx->store_primary->close_storage(ctx->store_primary);
free(ctx->store_primary);
ctx->store_secondary->close_storage(ctx->store_secondary);
free(ctx->store_secondary);

if (ctx->cache.tile) {
free(ctx->cache.tile);
Expand All @@ -226,7 +230,7 @@ struct storage_backend * init_storage_ro_composite(const char * connection_strin
return NULL;
#else
struct storage_backend * store = malloc(sizeof(struct storage_backend));
struct ro_composite_ctx * ctx = malloc(sizeof(struct ro_composite_ctx));
struct ro_composite_ctx * ctx = calloc(1, sizeof(struct ro_composite_ctx));
char * connection_string_primary;
char * connection_string_secondary;
char * tmp;
Expand All @@ -248,7 +252,23 @@ struct storage_backend * init_storage_ro_composite(const char * connection_strin
}

connection_string_secondary = strstr(connection_string, "}{");

if (connection_string_secondary == NULL) {
g_logger(G_LOG_LEVEL_ERROR, "init_storage_ro_composite: malformed connection string, missing '}{' separator: %s", connection_string);
free(ctx);
free(store);
return NULL;
}

connection_string_primary = malloc(strlen(connection_string) - strlen("composite:{") - strlen(connection_string_secondary) + 1);

if (connection_string_primary == NULL) {
g_logger(G_LOG_LEVEL_ERROR, "init_storage_ro_composite: failed to allocate memory for primary connection string");
free(ctx);
free(store);
return NULL;
}

memcpy(connection_string_primary, connection_string + strlen("composite:{"), strlen(connection_string) - strlen("composite:{") - strlen(connection_string_secondary));
connection_string_primary[strlen(connection_string) - strlen("composite:{") - strlen(connection_string_secondary)] = 0;
connection_string_secondary = strdup(connection_string_secondary + 2);
Expand All @@ -258,30 +278,61 @@ struct storage_backend * init_storage_ro_composite(const char * connection_strin
g_logger(G_LOG_LEVEL_DEBUG, "init_storage_ro_composite: Secondary storage backend: %s", connection_string_secondary);

tmp = strstr(connection_string_primary, ",");

if (tmp == NULL) {
g_logger(G_LOG_LEVEL_ERROR, "init_storage_ro_composite: malformed primary connection string, missing ',' separator: %s", connection_string_primary);
free(connection_string_primary);
free(connection_string_secondary);
free(ctx);
free(store);
return NULL;
}

memcpy(ctx->xmlconfig_primary, connection_string_primary, tmp - connection_string_primary);
ctx->xmlconfig_primary[tmp - connection_string_primary] = 0;
ctx->store_primary = init_storage_backend(tmp + 1);

if (ctx->store_primary == NULL) {
g_logger(G_LOG_LEVEL_ERROR, "init_storage_ro_composite: failed to initialise primary storage backend");
free(connection_string_primary);
free(connection_string_secondary);
free(ctx);
free(store);
return NULL;
}

tmp = strstr(connection_string_secondary, ",");

if (tmp == NULL) {
g_logger(G_LOG_LEVEL_ERROR, "init_storage_ro_composite: malformed secondary connection string, missing ',' separator: %s", connection_string_secondary);
free(connection_string_primary);
free(connection_string_secondary);
ctx->store_primary->close_storage(ctx->store_primary);
free(ctx->store_primary);
free(ctx);
free(store);
return NULL;
}

memcpy(ctx->xmlconfig_secondary, connection_string_secondary, tmp - connection_string_secondary);
ctx->xmlconfig_secondary[tmp - connection_string_secondary] = 0;
ctx->store_secondary = init_storage_backend(tmp + 1);

if (ctx->store_secondary == NULL) {
g_logger(G_LOG_LEVEL_ERROR, "init_storage_ro_composite: failed to initialise secondary storage backend");
free(connection_string_primary);
free(connection_string_secondary);
ctx->store_primary->close_storage(ctx->store_primary);
free(ctx->store_primary);
free(ctx);
free(store);
return NULL;
}

// The backends keep their own copies of what they need from these
free(connection_string_primary);
free(connection_string_secondary);

ctx->render_size = 256;

store->storage_ctx = ctx;
Expand Down
27 changes: 24 additions & 3 deletions src/store_ro_http_proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@

if (res != CURLE_OK) {
g_logger(G_LOG_LEVEL_ERROR, "ro_http_proxy_tile_fetch: failed to retrieve file: %s", curl_easy_strerror(res));
free(chunk.memory);
ctx->cache.x = -1;
ctx->cache.y = -1;
ctx->cache.z = -1;
Expand All @@ -126,6 +127,7 @@

if (res != CURLE_OK) {
g_logger(G_LOG_LEVEL_ERROR, "ro_http_proxy_tile_fetch: failed to retrieve HTTP code: %s", curl_easy_strerror(res));
free(chunk.memory);
ctx->cache.x = -1;
ctx->cache.y = -1;
ctx->cache.z = -1;
Expand All @@ -150,19 +152,31 @@
case 404: {
if (ctx->cache.tile != NULL) {
free(ctx->cache.tile);
ctx->cache.tile = NULL;
}

free(chunk.memory);
ctx->cache.st_stat.size = -1;
ctx->cache.st_stat.expired = 0;
break;
}
}

default: {
// Do not cache anything for unexpected responses, otherwise the previously
// cached tile would be served for these coordinates
g_logger(G_LOG_LEVEL_ERROR, "ro_http_proxy_tile_fetch: unexpected HTTP response code %li", httpCode);
free(chunk.memory);
ctx->cache.x = -1;
ctx->cache.y = -1;
ctx->cache.z = -1;
return -1;
}
}

ctx->cache.x = x;
ctx->cache.y = y;
ctx->cache.z = z;
strcpy(ctx->cache.xmlname, xmlconfig);
snprintf(ctx->cache.xmlname, sizeof(ctx->cache.xmlname), "%s", xmlconfig);
return 1;
}
}
Expand All @@ -172,7 +186,12 @@
struct ro_http_proxy_ctx * ctx = (struct ro_http_proxy_ctx *)(store->storage_ctx);

if (ro_http_proxy_tile_retrieve(store, xmlconfig, options, x, y, z) > 0) {
if (ctx->cache.st_stat.size > sz) {
if (ctx->cache.st_stat.size < 0) {
// Cached 404
return -1;
}

if ((size_t)ctx->cache.st_stat.size > sz) {
g_logger(G_LOG_LEVEL_ERROR, "ro_http_proxy_tile_read: size was too big, overrun %lu %li", sz, ctx->cache.st_stat.size);
return -1;
}
Expand Down Expand Up @@ -299,6 +318,7 @@

if (res != CURLE_OK) {
g_logger(G_LOG_LEVEL_ERROR, "init_storage_ro_http_proxy: failed to initialise global curl: %s", curl_easy_strerror(res));
free(ctx->baseurl);
free(ctx);
free(store);
return NULL;
Expand All @@ -308,6 +328,7 @@

if (!ctx->ctx) {
g_logger(G_LOG_LEVEL_ERROR, "init_storage_ro_http_proxy: failed to initialise curl");
free(ctx->baseurl);
free(ctx);
free(store);
return NULL;
Expand Down
31 changes: 23 additions & 8 deletions tests/gen_tile_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1188,20 +1188,35 @@ TEST_CASE("rados storage-backend", "RADOS Tile storage backend")

TEST_CASE("ro_composite storage-backend", "RO Composite Tile storage backend")
{
#ifndef HAVE_CAIRO
SECTION("storage/initialise", "should return NULL") {
int found;
std::string err_log_lines, out_log_lines;
int found;
std::string err_log_lines, out_log_lines;
std::string tile_dir = P_tmpdir;
std::string valid = "composite:{default," + tile_dir + "}{default," + tile_dir + "}";

start_capture();
REQUIRE(init_storage_backend("composite:{") == NULL);
std::tie(err_log_lines, out_log_lines) = end_capture();
start_capture();
struct storage_backend *store = init_storage_backend(valid.c_str());
std::tie(err_log_lines, out_log_lines) = end_capture();

if (store == NULL) {
// Composite support depends on HAVE_CAIRO as seen by the C sources, which can differ
// from what this C++ file sees (e.g. Autotools builds), so check at run time
found = err_log_lines.find("init_storage_ro_coposite: Support for compositing storage has not been compiled into this program");
REQUIRE(found > -1);
return;
}

#endif
// Closing must free the inner backends and not touch the (never used) tile cache
store->close_storage(store);
free(store);

start_capture();
// Missing "}{" separator
REQUIRE(init_storage_backend(("composite:{default," + tile_dir + "}").c_str()) == NULL);
// Primary backend fails to initialise
REQUIRE(init_storage_backend(("composite:{default,/does/not/exist}{default," + tile_dir + "}").c_str()) == NULL);
// Secondary backend fails to initialise
REQUIRE(init_storage_backend(("composite:{default," + tile_dir + "}{default,/does/not/exist}").c_str()) == NULL);
end_capture();
}

TEST_CASE("ro_http_proxy storage-backend", "RO HTTP Proxy Tile storage backend")
Expand Down
Loading