Example #1
0
int mapcache_imageio_is_valid_format(mapcache_context *ctx, mapcache_buffer *buffer)
{
  mapcache_image_format_type t = mapcache_imageio_header_sniff(ctx,buffer);
  if(t==GC_PNG || t==GC_JPEG) {
    return MAPCACHE_TRUE;
  } else {
    return MAPCACHE_FALSE;
  }
}
Example #2
0
mapcache_image* mapcache_imageio_decode(mapcache_context *ctx, mapcache_buffer *buffer)
{
  mapcache_image_format_type type = mapcache_imageio_header_sniff(ctx,buffer);
  if(type == GC_PNG) {
    return _mapcache_imageio_png_decode(ctx,buffer);
  } else if(type == GC_JPEG) {
    return _mapcache_imageio_jpeg_decode(ctx,buffer);
  } else {
    ctx->set_error(ctx, 500, "mapcache_imageio_decode: unrecognized image format");
    return NULL;
  }
}
Example #3
0
mapcache_http_response *mapcache_core_get_map(mapcache_context *ctx, mapcache_request_get_map *req_map)
{
  mapcache_image_format *format = NULL;
  mapcache_http_response *response;
  mapcache_map *basemap = NULL;
  char *timestr;
#ifdef DEBUG
  if(req_map->nmaps ==0) {
    ctx->set_error(ctx,500,"BUG: get_map called with 0 maps");
    return NULL;
  }
#endif


  if(req_map->getmap_strategy == MAPCACHE_GETMAP_ERROR) {
    ctx->set_error(ctx, 404, "full wms support disabled");
    return NULL;
  }

  format = NULL;
  response = mapcache_http_response_create(ctx->pool);


  if(req_map->getmap_strategy == MAPCACHE_GETMAP_ASSEMBLE) {
    basemap = mapcache_assemble_maps(ctx, req_map->maps, req_map->nmaps, req_map->resample_mode);
    if(GC_HAS_ERROR(ctx)) return NULL;
  } else if(!ctx->config->non_blocking && req_map->getmap_strategy == MAPCACHE_GETMAP_FORWARD) {
    int i;
    basemap = req_map->maps[0];
    for(i=0; i<req_map->nmaps; i++) {
      if(!req_map->maps[i]->tileset->source) {
        ctx->set_error(ctx,404,"cannot forward request for tileset %s: no source configured",
                       req_map->maps[i]->tileset->name);
        return NULL;
      }
    }
    basemap->tileset->source->render_map(ctx, basemap);
    if(GC_HAS_ERROR(ctx)) return NULL;
    if(req_map->nmaps>1) {
      if(!basemap->raw_image) {
        basemap->raw_image = mapcache_imageio_decode(ctx,basemap->encoded_data);
        if(GC_HAS_ERROR(ctx)) return NULL;
      }
      for(i=1; i<req_map->nmaps; i++) {
        mapcache_map *overlaymap = req_map->maps[i];
        overlaymap->tileset->source->render_map(ctx, overlaymap);
        if(GC_HAS_ERROR(ctx)) return NULL;
        if(!overlaymap->raw_image) {
          overlaymap->raw_image = mapcache_imageio_decode(ctx,overlaymap->encoded_data);
          if(GC_HAS_ERROR(ctx)) return NULL;
        }
        if(GC_HAS_ERROR(ctx)) return NULL;
        mapcache_image_merge(ctx,basemap->raw_image,overlaymap->raw_image);
        if(GC_HAS_ERROR(ctx)) return NULL;
        if(!basemap->expires || overlaymap->expires<basemap->expires) basemap->expires = overlaymap->expires;
      }
    }
  } else {
    ctx->set_error(ctx,400,"failed getmap, readonly mode");
    return NULL;
  }

  if(basemap->raw_image) {
    format = req_map->getmap_format; /* always defined, defaults to JPEG */
    response->data = format->write(ctx,basemap->raw_image,format);
    if(GC_HAS_ERROR(ctx)) {
      return NULL;
    }
  } else {
    /* this case happens when we have a forward strategy for a single tileset */
#ifdef DEBUG
    if(!basemap->encoded_data) {
      ctx->set_error(ctx,500,"###BUG### core_get_map failed with null encoded_data");
      return NULL;
    }
#endif
    response->data = basemap->encoded_data;
  }

  /* compute the content-type */
  if(format && format->mime_type) {
    apr_table_set(response->headers,"Content-Type",format->mime_type);
  } else {
    mapcache_image_format_type t = mapcache_imageio_header_sniff(ctx,response->data);
    if(t == GC_PNG)
      apr_table_set(response->headers,"Content-Type","image/png");
    else if(t == GC_JPEG)
      apr_table_set(response->headers,"Content-Type","image/jpeg");
  }

  /* compute expiry headers */
  if(basemap->expires) {
    apr_time_t now = apr_time_now();
    apr_time_t additional = apr_time_from_sec(basemap->expires);
    apr_time_t texpires = now + additional;
    apr_table_set(response->headers, "Cache-Control",
                  apr_psprintf(ctx->pool, "max-age=%d", basemap->expires));
    timestr = apr_palloc(ctx->pool, APR_RFC822_DATE_LEN);
    apr_rfc822_date(timestr, texpires);
    apr_table_setn(response->headers, "Expires", timestr);
  }

  response->mtime = basemap->mtime;
  return response;
}
Example #4
0
mapcache_http_response *mapcache_core_get_tile(mapcache_context *ctx, mapcache_request_get_tile *req_tile)
{
  int expires = 0;
  mapcache_http_response *response;
  int i,is_empty=1 /* response image is initially empty */;
  char *timestr;
  mapcache_image *base=NULL;
  mapcache_image_format *format = NULL;

#ifdef DEBUG
  if(req_tile->ntiles ==0) {
    ctx->set_error(ctx,500,"BUG: get_tile called with 0 tiles");
    return NULL;
  }
#endif
  response = mapcache_http_response_create(ctx->pool);


  mapcache_prefetch_tiles(ctx,req_tile->tiles,req_tile->ntiles);
  if(GC_HAS_ERROR(ctx))
    return NULL;

  /* loop through tiles, and eventually merge them vertically together */
  for(i=0; i<req_tile->ntiles; i++) {
    mapcache_tile *tile = req_tile->tiles[i]; /* shortcut */
    if(tile->mtime && (tile->mtime < response->mtime || response->mtime == 0))
      response->mtime = tile->mtime;
    if(tile->expires && (tile->expires < expires || expires == 0)) {
      expires = tile->expires;
    }
    
    if(tile->nodata) {
      /* treat the special case where the cache explicitely stated that the
       tile was empty, and we don't have any vertical merging to do */
      if(tile->encoded_data && req_tile->ntiles == 1) {
        response->data = tile->encoded_data;
        /* we don't touch is_empty, as we have access to the encoded empty image, but the
         resulting tile is empty */
      }
      continue;
    }
    
    /* treat the most common case: 
     - we have a single tile request (i.e. isempty is true)
     - the cache returned the encoded image
     */
    if(is_empty && tile->encoded_data) {
      response->data = tile->encoded_data;
      /* just in case we also have the raw image data available, keep a ref to it
       if we need to merge another tile ontop of it*/
      if(tile->raw_image) {
        base = tile->raw_image;
      }
      is_empty = 0; /* we now know we might need to do some vertical merging */
      continue;
    }

    /* if we're here, either
     * - we need to merge the current tile onto the previous one(s), or
     * - we only have the tile's raw data available
     */

    if(!is_empty) {
      /* we have an existing tile, so we know we need to merge the current one into it */
      if(!base) {
        /* the existing tile has not been decoded yet, but we need the access to the raw pixels*/
        base = mapcache_imageio_decode(ctx, response->data);
        if(!base) return NULL;
      }
      response->data = NULL; /* the encoded data is now obsolete, as we will be merging the current tile */

      /* we need to access the current tile's pixel data */
      if(!tile->raw_image) {
        tile->raw_image = mapcache_imageio_decode(ctx,tile->encoded_data);
        if(!tile->raw_image) return NULL;
      }
      mapcache_image_merge(ctx, base, tile->raw_image);
    } else {
      /* we don't need to merge onto an existing tile and don't have access to the tile's encoded data.
       * 
       * we don't encode the tile's raw image data just yet because we might need to merge another one on top
       * of it later.
       */
      base = tile->raw_image;
      is_empty = 0;
    }
  }

  if(!response->data) {
    /* we need to encode the raw image data*/
    if(base) {
      if(req_tile->format) {
        format = req_tile->format;
      } else {
        format = req_tile->tiles[0]->tileset->format;
        if(!format) {
          format = ctx->config->default_image_format; /* this one is always defined */
        }
      }
      response->data = format->write(ctx, base, format);
      if(GC_HAS_ERROR(ctx)) {
        return NULL;
      }
    } else {
#ifdef DEBUG
      if(!is_empty) {
        ctx->set_error(ctx,500,"BUG: no image data to encode, but tile not marked as empty");
        return NULL;
      }
#endif
      unsigned char empty[5] = {'#',0,0,0,0};
      response->data = mapcache_empty_png_decode(ctx,empty,&is_empty); /* is_empty is unchanged and left to 1 */
      format = mapcache_configuration_get_image_format(ctx->config,"PNG8");
    }
  }
  
  /* compute the content-type */
  mapcache_image_format_type t = mapcache_imageio_header_sniff(ctx,response->data);
  if(t == GC_PNG)
    apr_table_set(response->headers,"Content-Type","image/png");
  else if(t == GC_JPEG)
    apr_table_set(response->headers,"Content-Type","image/jpeg");

  /* compute expiry headers */
  if(expires) {
    apr_time_t now = apr_time_now();
    apr_time_t additional = apr_time_from_sec(expires);
    apr_time_t texpires = now + additional;
    apr_table_set(response->headers, "Cache-Control",apr_psprintf(ctx->pool, "max-age=%d", expires));
    timestr = apr_palloc(ctx->pool, APR_RFC822_DATE_LEN);
    apr_rfc822_date(timestr, texpires);
    apr_table_setn(response->headers, "Expires", timestr);
  }

  return response;
}
Example #5
0
mapcache_http_response *mapcache_core_get_tile(mapcache_context *ctx, mapcache_request_get_tile *req_tile)
{
  int expires = 0;
  mapcache_http_response *response;
  int i,first = -1;
  int ntiles_with_data = 0;
  char *timestr;
  mapcache_image *base=NULL,*overlay;
  mapcache_image_format *format = NULL;

#ifdef DEBUG
  if(req_tile->ntiles ==0) {
    ctx->set_error(ctx,500,"BUG: get_tile called with 0 tiles");
    return NULL;
  }
#endif
  expires = 0;
  response = mapcache_http_response_create(ctx->pool);


  mapcache_prefetch_tiles(ctx,req_tile->tiles,req_tile->ntiles);
  if(GC_HAS_ERROR(ctx))
    return NULL;

  /* count how many tiles actually contain data */
  for(i=0; i<req_tile->ntiles; i++) {
    /* add 1 if tile->nodata == 0 */
    ntiles_with_data -= req_tile->tiles[i]->nodata - 1;
  }
  if(ntiles_with_data == 0) {
    ctx->set_error(ctx,404,
                   "no tiles containing image data could be retrieved (not in cache, and read-only tileset or no source configured)");
    return NULL;
  }
  /* this loop retrieves the tiles from the caches, and eventually decodes and merges them together
   * if multiple tiles were asked for */
  for(i=0; i<req_tile->ntiles; i++) {
    mapcache_tile *tile = req_tile->tiles[i];
    if(tile->nodata) continue;
    if(first == -1) {
      first = i;
      response->mtime = tile->mtime;
      expires = tile->expires;
      /* if we have multiple tiles to merge, decode the image data */
      if(ntiles_with_data>1) {
        if(!tile->raw_image) {
          tile->raw_image = mapcache_imageio_decode(ctx, tile->encoded_data);
          if(!tile->raw_image) return NULL;
        }
        base = tile->raw_image;
      }
    } else {
      if(response->mtime < tile->mtime)
        response->mtime = tile->mtime;
      if(tile->expires < expires) {
        expires = tile->expires;
      }
      if(!tile->raw_image) {
        tile->raw_image = mapcache_imageio_decode(ctx, tile->encoded_data);
        if(!tile->raw_image) return NULL;
      }
      overlay = tile->raw_image;
      mapcache_image_merge(ctx, base, overlay);
      if(GC_HAS_ERROR(ctx)) {
        return NULL;
      }
    }
  }
  format = NULL;

  /* if we had more than one tile, we need to encode the raw image data into a mapcache_buffer */
  if(ntiles_with_data > 1) {
    if(req_tile->format) {
      format = req_tile->format;
    } else {
      format = req_tile->tiles[first]->tileset->format;
      if(!format) {
        format = ctx->config->default_image_format; /* this one is always defined */
      }
    }
    response->data = format->write(ctx, base, format);
    if(GC_HAS_ERROR(ctx)) {
      return NULL;
    }
  } else {
    response->data = req_tile->tiles[first]->encoded_data;
    format = req_tile->tiles[first]->tileset->format;
  }

  /* compute the content-type */
  if(format && format->mime_type) {
    apr_table_set(response->headers,"Content-Type",format->mime_type);
  } else {
    mapcache_image_format_type t = mapcache_imageio_header_sniff(ctx,response->data);
    if(t == GC_PNG)
      apr_table_set(response->headers,"Content-Type","image/png");
    else if(t == GC_JPEG)
      apr_table_set(response->headers,"Content-Type","image/jpeg");
  }

  /* compute expiry headers */
  if(expires) {
    apr_time_t now = apr_time_now();
    apr_time_t additional = apr_time_from_sec(expires);
    apr_time_t texpires = now + additional;
    apr_table_set(response->headers, "Cache-Control",apr_psprintf(ctx->pool, "max-age=%d", expires));
    timestr = apr_palloc(ctx->pool, APR_RFC822_DATE_LEN);
    apr_rfc822_date(timestr, texpires);
    apr_table_setn(response->headers, "Expires", timestr);
  }

  return response;
}
Example #6
0
/**
 * \brief push tile data to riak
 *
 * writes the content of mapcache_tile::data to the configured riak instance(s)
 * \private \memberof mapcache_cache_riak
 * \sa mapcache_cache::tile_set()
 */
static void _mapcache_cache_riak_set(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile) {
    char *key,*content_type;
    int error;
    int connect_error = RIACK_SUCCESS;
    int retries = 3;
    struct RIACK_OBJECT object;
    struct RIACK_CONTENT content;
    struct RIACK_PUT_PROPERTIES properties;
    struct RIACK_CLIENT *client;
    mapcache_pooled_connection *pc;
    mapcache_cache_riak *cache = (mapcache_cache_riak*)pcache;

    memset(&content, 0, sizeof(struct RIACK_CONTENT));
    memset(&object, 0, sizeof(struct RIACK_OBJECT));
    memset(&properties, 0, sizeof(struct RIACK_PUT_PROPERTIES));

    //Use Buckets defaults instead of setting the read/write attributes
    /*
    properties.w_use = 1;
    properties.w = 1;

    properties.dw_use = 1;
    properties.dw = 0;*/


    key = mapcache_util_get_tile_key(ctx, tile, NULL, " \r\n\t\f\e\a\b", "#");
    GC_CHECK_ERROR(ctx);

    if (!tile->encoded_data) {
        tile->encoded_data = tile->tileset->format->write(ctx, tile->raw_image, tile->tileset->format);
        GC_CHECK_ERROR(ctx);
    }
    content_type = tile->tileset->format?(tile->tileset->format->mime_type?tile->tileset->format->mime_type:NULL):NULL;

    if(!content_type) {
        /* compute the content-type */
        mapcache_image_format_type t = mapcache_imageio_header_sniff(ctx,tile->encoded_data);
        if(t == GC_PNG)
            content_type = "image/png";
        else if(t == GC_JPEG)
            content_type = "image/jpeg";
    }

    pc = _riak_get_connection(ctx, cache, tile);
    GC_CHECK_ERROR(ctx);
    client = pc->connection;

    // Set up the riak object to put.  Need to do this after we get the client connection
    object.bucket.value = cache->bucket.value;
    object.bucket.len = cache->bucket.len;
    object.key.value = key;
    object.key.len = strlen(key);
    object.vclock.len = 0;
    object.content_count = 1;
    object.content = &content;
    content.content_type.value = content_type;
    content.content_type.len = content_type?strlen(content_type):0;
    content.data = (uint8_t*)tile->encoded_data->buf;
    content.data_len = tile->encoded_data->size;

    // If we get an error it is advised that we call reconnect.  It also appears
    // that every now and then we get an error and need to retry once again to
    // get it to work.
    do
    {
        error = riack_put(client, object, 0, &properties);
        if (error != RIACK_SUCCESS) {
            ctx->log(ctx, MAPCACHE_WARN, "Retry %d in riak_set for tile %s from cache %s due to eror %d", (4 - retries), key, cache->cache.name, error);
            for (connect_error = riack_reconnect(client);
                    connect_error != RIACK_SUCCESS && retries > 0;
                    connect_error = riack_reconnect(client))
            {
                --retries;
            }

            --retries;
        }
    }
    while (error != RIACK_SUCCESS && retries >= 0);

    if (connect_error != RIACK_SUCCESS)
        mapcache_connection_pool_invalidate_connection(ctx,pc);
    else
        mapcache_connection_pool_release_connection(ctx,pc);

    if (error != RIACK_SUCCESS)
    {
        ctx->set_error(ctx, 500, "failed to store tile %s to cache %s due to error %d.", key, cache->cache.name, error);
    }
}