Exemplo n.º 1
0
void testGet(dmlite_context* context)
{
  SECTION("GET");
  
  /* Mock returns always a location with two chunks */
  dmlite_location* loc;
  TEST_CONTEXT_CALL_PTR(loc, context, dmlite_get, "/file");
  
  TEST_ASSERT_EQUAL(2, loc->nchunks);
  
  TEST_ASSERT_STR_EQUAL("host1.cern.ch", loc->chunks[0].host);
  TEST_ASSERT_STR_EQUAL("/storage/chunk01", loc->chunks[0].path);
  TEST_ASSERT_EQUAL(0, loc->chunks[0].offset);
  TEST_ASSERT_EQUAL(100, loc->chunks[0].size);
          
  TEST_ASSERT_STR_EQUAL("host2.cern.ch", loc->chunks[1].host);
  TEST_ASSERT_STR_EQUAL("/storage/chunk02", loc->chunks[1].path);
  TEST_ASSERT_EQUAL(101, loc->chunks[1].offset);
  TEST_ASSERT_EQUAL(50, loc->chunks[1].size);
  
  /* Second has an extra */
  char         buffer[64];
  dmlite_any*  extra = dmlite_any_dict_get(loc->chunks[1].extra, "token");
  dmlite_any_to_string(extra, buffer, sizeof(buffer));
  TEST_ASSERT_STR_EQUAL("123456789", buffer);
  dmlite_any_free(extra);
  
  dmlite_location_free(context, loc);
}
Exemplo n.º 2
0
void testWrite(dmlite_context* context)
{
  dmlite_fd*       file;
  dmlite_any_dict* dict = dmlite_any_dict_new();
  char             buffer[64];
  
  SECTION("Read");
  
  /* Good to open */
  dmlite_any* token = dmlite_any_new_string("987654321");
  dmlite_any_dict_insert(dict, "token", token);
  dmlite_any_free(token);
  TEST_CONTEXT_CALL_PTR(file, context, dmlite_fopen, "/file", O_RDWR, dict);
  
  /* Write a chunk */
  TEST_ASSERT_EQUAL(10, dmlite_fwrite(file, "123456789", 10));
  
  /* Seek and read it back */
  TEST_ASSERT_EQUAL(0, dmlite_fseek(file, 0, SEEK_SET));
  TEST_ASSERT_EQUAL(10, dmlite_fread(file, buffer, 10));
  TEST_ASSERT_STR_EQUAL("123456789", buffer);
  
  
  /* Free */
  TEST_ASSERT_EQUAL(0, dmlite_fclose(file));
  dmlite_any_dict_free(dict);
}
Exemplo n.º 3
0
void testPut(dmlite_context* context)
{
  char buffer[64];
  
  SECTION("PUT");
  
  /* Mock returns always one single location with one token */
  dmlite_location* loc;
  TEST_CONTEXT_CALL_PTR(loc, context, dmlite_put, "/file");
  
  TEST_ASSERT_EQUAL(1, loc->nchunks);
  
  TEST_ASSERT_STR_EQUAL("host1.cern.ch", loc->chunks[0].host);
  TEST_ASSERT_STR_EQUAL("/storage/chunk01", loc->chunks[0].path);
  TEST_ASSERT_EQUAL(0, loc->chunks[0].offset);
  TEST_ASSERT_EQUAL(0, loc->chunks[0].size);
  
    
  dmlite_any*  extra = dmlite_any_dict_get(loc->chunks[0].extra, "token");
  dmlite_any_to_string(extra, buffer, sizeof(buffer));
  TEST_ASSERT_STR_EQUAL("987654321", buffer);
  dmlite_any_free(extra);
  
  dmlite_location_free(context, loc);
  
  /* A donewriting without token will fail */
  dmlite_any_dict* dict = dmlite_any_dict_new();
  TEST_ASSERT_EQUAL(DM_FORBIDDEN, dmlite_donewriting(context,
                                                     "/storage/chunk01", dict));
  
  /* With token */
  dmlite_any* token = dmlite_any_new_string("987654321");
  dmlite_any_dict_insert(dict, "token", token);
  
  TEST_CONTEXT_CALL(context, dmlite_donewriting,
                    "/storage/chunk01", dict);
  
  dmlite_any_free(token);
  dmlite_any_dict_free(dict);
}
Exemplo n.º 4
0
void testRead(dmlite_context* context)
{
  dmlite_fd*       file;
  dmlite_any_dict* dict = dmlite_any_dict_new();
  char             buffer[64];
  memset(buffer, 0, sizeof(buffer));
  
  SECTION("Read");
  
  /* Bad token */
  file = dmlite_fopen(context, "/file", O_RDONLY, dict);
  TEST_ASSERT_EQUAL(NULL, file);
  TEST_ASSERT_EQUAL(DM_FORBIDDEN, dmlite_errno(context));
          
  /* Open non-existing */
  file = dmlite_fopen(context, "/does-not-exist", O_RDONLY, dict);
  TEST_ASSERT_EQUAL(NULL, file);
  TEST_ASSERT_EQUAL(DM_NO_SUCH_FILE, dmlite_errno(context));
  
  /* Good to open */
  dmlite_any* token = dmlite_any_new_string("123456789");
  dmlite_any_dict_insert(dict, "token", token);
  dmlite_any_free(token);
  TEST_CONTEXT_CALL_PTR(file, context, dmlite_fopen, "/file", O_RDONLY, dict);
  
  /* Read */
  TEST_ASSERT_EQUAL(4, dmlite_fread(file, buffer, 4));
  buffer[5] = '\0';
  TEST_ASSERT_STR_EQUAL("abcd", buffer);
  TEST_ASSERT_EQUAL(4, dmlite_fread(file, buffer, 4));
  buffer[5] = '\0';
  TEST_ASSERT_STR_EQUAL("efgh", buffer);
  
  /* Seek and read */
  TEST_ASSERT_EQUAL(0, dmlite_fseek(file, 10, SEEK_SET));
  TEST_ASSERT_EQUAL(4, dmlite_fread(file, buffer, 4));
  buffer[5] = '\0';
  TEST_ASSERT_STR_EQUAL("klmn", buffer);
  
  TEST_ASSERT_EQUAL(14, dmlite_ftell(file));
  
  TEST_ASSERT_EQUAL(0, dmlite_feof(file));
  
  /* Free */
  TEST_ASSERT_EQUAL(0, dmlite_fclose(file));
  dmlite_any_dict_free(dict);
}
Exemplo n.º 5
0
void testGetPools(dmlite_context* context)
{
  dmlite_pool* pools;
  unsigned     nPools;
  char         buffer[64];
  
  SECTION("Get pools");
  
  /* Mock should return 1 */
  TEST_CONTEXT_CALL(context, dmlite_getpools, &nPools, &pools);
  TEST_ASSERT_EQUAL(1, nPools);
  
  TEST_ASSERT_STR_EQUAL("mock", pools[0].pool_type);
  TEST_ASSERT_STR_EQUAL("hardcoded", pools[0].pool_name);
  
  /* There is one dummy extra */
  dmlite_any* extra = dmlite_any_dict_get(pools[0].extra, "extra");
  dmlite_any_to_string(extra, buffer, sizeof(buffer));
  TEST_ASSERT_STR_EQUAL("something", buffer);
  dmlite_any_free(extra);
  
  /* Free */
  TEST_ASSERT_EQUAL(0, dmlite_pools_free(context, nPools, pools));
}
Exemplo n.º 6
0
/**
 * Open a stream. Used for PUT
 * @param resource The resource to open
 * @param mode     The mode (basically, trucate or random, which we don't support)
 * @param stream   Where to put the created structure
 * @return         NULL on success
 */
static dav_error *dav_ns_open_stream(const dav_resource *resource,
                                      dav_stream_mode mode,
                                      dav_stream **stream)
{
  dav_resource_private     *info;
  unsigned                  has_range;
  const char               *range, *length;
  int                       e;

  info = resource->info;
  
  /* Must be writable (if we are here, they want to write) */
  if (!(info->d_conf->flags & DAV_NS_WRITE))
    return dav_shared_new_error(info->request, NULL, HTTP_FORBIDDEN,
                                "Configured as read-only endpoint (%s)",
                                resource->uri);

  /* If content-length is 0, call create instead of put! */
  length = apr_table_get(info->request->headers_in, "content-length");
  if (length != NULL) {
    size_t clen = atol(length);
    if (clen == 0) {
      ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0,
                    info->request,
                    "PUT with content-length 0. Creating ns entry.");

      if (dmlite_create(info->ctx, info->sfn, 0644) != 0)
        return dav_shared_new_error(info->request, info->ctx, 0,
                                    "Could not create empty file %s", info->sfn);

      *stream = (dav_stream*)calloc(1, sizeof(dav_stream));

      return NULL;
    }
  }

  /* NS alone doesn't support PUTs with content! */
  if (info->s_conf->type == DAV_NS_NODE_LFC)
    return dav_shared_new_error(info->request, NULL, HTTP_NOT_IMPLEMENTED,
                                "LFC does not support PUTs");

  /*  Range header? */
  range = apr_table_get(info->request->headers_in, "content-range");
  has_range = (range != NULL);
  if (has_range) {
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0,
                  info->request,
                  "Range: %s", range);
  }

  /* If token not set, call dm_put and see where do we have to go */
  if (info->space_token != NULL) {
    dmlite_any* any = dmlite_any_new_string(info->space_token);
    e = dmlite_set(info->ctx, "SpaceToken", any);
    dmlite_any_free(any);
    if (e)
      return dav_shared_new_error(info->request, info->ctx, 0,
                                 "Could not set the space token %s", info->space_token);
  }
  
  dmlite_location *location; 
  location = dmlite_put(info->ctx, info->sfn);
  switch (dmlite_errno(info->ctx)) {
    case 0:
      break;
    case DM_INVALID_VALUE:
      return dav_shared_new_error(info->request, info->ctx, HTTP_BAD_REQUEST,
                                  "Can not get the space token %s",
                                  info->space_token);
    default:
      return dav_shared_new_error(info->request, info->ctx, 0, "Can not put %s",
                                  info->sfn);
  }      

  /* Redirect */
  info->redirect = apr_psprintf(resource->pool, "%s://%s%s%s",
                                info->d_conf->redir_scheme,
                                location->chunks[0].host,
                                location->chunks[0].path,
                                dav_shared_build_extra(resource->pool,
                                                       location->chunks[0].extra));

  ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0,
                info->request,
                "PUT request to be done in %s",
                info->redirect);

  apr_table_set(info->request->headers_out,
                "Location", info->redirect);
  
  dmlite_location_free(info->ctx, location);
  
  /* Standard says 301/302, but some clients will retry in that case with a GET.
   * 307 is unambiguous */
  return dav_new_error(resource->pool, HTTP_TEMPORARY_REDIRECT, 0,
                       info->redirect);
}
Exemplo n.º 7
0
/**
 * Get the location of the file
 * @param info Input/output parameter. sfn must be set. location will be set.
 * @param pool Pool for memory allocation
 * @return NULL on success
 */
dav_error *dav_ns_get_location(dav_resource_private *info,
                               apr_pool_t *pool)
{
  dmlite_replica *replicas;
  unsigned        n_replicas, i;
  char           *referrer, *p;
  dmlite_url      url;

  /* If there is a rejected list, this is a fallback */
  if ((info->s_conf->type == DAV_NS_NODE_LFC) &&
      (info->forbidden_str != NULL || info->notfound_str != NULL)) {
    int64_t *rejected_ids, id;
    int      n_forbidden = 0, n_notfound = 0, n_total = 0;

    /* Count first to allocate */
    if (info->forbidden_str != NULL) {
      n_forbidden = 1;
      for (i = 0; info->forbidden_str[i] != '\0'; ++i) {
        if (info->forbidden_str[i] == ',')
          ++n_forbidden;
      }
    }
    if (info->notfound_str != NULL) {
      n_notfound = 1;
      for (i = 0; info->notfound_str[i] != '\0'; ++i) {
        if (info->notfound_str[i] == ',')
          ++n_notfound;
      }
    }

    /* Build rejected list */
    n_total      = n_forbidden + n_notfound;
    rejected_ids = apr_pcalloc(pool, sizeof(int64_t) * n_total);
    i            = 0;

    p = (char*)info->forbidden_str;
    while (p != NULL && *p != '\0') {
      errno = 0;
      id    = strtol(p, &p, 0);
      if (errno == 0)
        rejected_ids[i++] = id;
      if (*p != '\0')
        ++p;
    }

    p = (char*)info->notfound_str;
    while (p != NULL && *p != '\0') {
      errno = 0;
      id    = strtol(p, &p, 0);
      if (errno == 0)
        rejected_ids[i++] = id;
      if (*p != '\0')
        ++p;
    }

    dmlite_any* any = dmlite_any_new_long_array(n_total, rejected_ids);    
    i = dmlite_set(info->ctx, "ExcludeReplicas", any);
    dmlite_any_free(any);
    if (i != 0) {
      return dav_shared_new_error(info->request, info->ctx, 0,
                                  "Error on fall-back method");
    }
  }

  /* Logic here depends on the node type */
  dmlite_location *location;
  switch (info->s_conf->type) {
    case DAV_NS_NODE_HEAD:
      /* Ask for the best one */
      location = dmlite_get(info->ctx, info->sfn);
      switch(dmlite_errno(info->ctx)) {
        case 0:
          break;
        case DM_FORBIDDEN:
          info->redirect = dav_shared_build_aggregation_url(info->request->pool,
                                                            info->n_replicas,
                                                            (const char**)info->replicas,
                                                            info->replicas_ids,
                                                            info->forbidden_str,
                                                            info->notfound_str,
                                                            info->r_id, -1);
          if (info->redirect != NULL) {
            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0,
                          info->request,
                          "Access forbidden for %s, forwarded to %s",
                          info->sfn, info->redirect);
            return NULL;
          }
        default:
          return dav_shared_new_error(info->request, info->ctx, 0, NULL);
      }
      
      /* Destination URL */
      info->redirect = apr_psprintf(pool, "%s://%s%s%s",
                                    info->d_conf->redir_scheme,
                                    location->chunks[0].host,
                                    location->chunks[0].path,
                                    dav_shared_build_extra(pool, location->chunks[0].extra));
      
      dmlite_location_free(info->ctx, location);
      break;
      
    /* LFC wants the whole list */
    case DAV_NS_NODE_LFC:
      if (dmlite_getreplicas(info->ctx, info->sfn, &n_replicas, &replicas) != 0)
        return dav_shared_new_error(info->request, info->ctx, 0, NULL);

      /* Initialize */
      info->n_replicas    = n_replicas + 1;
      info->forbidden_str = NULL;
      info->notfound_str  = NULL;

      /* Build the referrer */
      referrer = apr_psprintf(pool, "%s://%s:%u%s",
                              info->d_conf->redir_scheme,
                              info->request->hostname,
                              info->request->server->port,
                              info->request->uri);

      /* Build the replica list, skipping the first */
      info->replicas     = apr_pcalloc(pool, sizeof(char*) * info->n_replicas);
      info->replicas_ids = apr_pcalloc(pool, sizeof(int64_t) * info->n_replicas);
      for (i = 0; i < n_replicas && i < info->d_conf->max_replicas; ++i) {
        dmlite_parse_url(replicas[i].rfn, &url);
        info->replicas[i]     = dav_shared_build_url(pool, &url, info->d_conf->redir_scheme);
        info->replicas_ids[i] = replicas[i].replicaid;
      }

      /* Append ourselves */
      info->replicas[i]     = referrer;
      info->replicas_ids[i] = -1;

      /* Build the definitive URL */
      info->redirect = dav_shared_build_aggregation_url(info->request->pool,
                                                        info->n_replicas,
                                                        (const char**)info->replicas,
                                                        info->replicas_ids,
                                                        info->forbidden_str,
                                                        info->notfound_str,
                                                        -1, -1);

      /* Clean up */
      dmlite_replicas_free(info->ctx, n_replicas, replicas);

      break;
    default:
      return dav_shared_new_error(info->request, NULL, HTTP_INTERNAL_SERVER_ERROR,
                                  "Invalid node type configured");
  }

  return NULL;
}