/** * Function called for the configuration parameter NSHost * @param cmd Lots of information about the configuration contexts (as pool) * @param config Unused pointer * @param arg The value of the parameter * @return NULL on success. An error string otherwise */ static const char *dav_ns_cmd_dmlite(cmd_parms *cmd, void *config, const char *arg) { dav_ns_server_conf *conf; conf = ap_get_module_config(cmd->server->module_config, &lcgdm_ns_module); if (dmlite_manager_load_configuration(conf->manager, arg) != 0) return apr_psprintf(cmd->pool, "Could not load %s (%s)", arg, dmlite_manager_error(conf->manager)); return NULL; }
/** * This function is used internally to create new resources. * @param r The request to associate. * @param sfn The SFN to link to the resource. * @param uri The URI (without the query!) * @param user The associated user. If NULL, will be queried and initialized. * @param resource Where to put it. * @return NULL on success. */ static dav_error *dav_ns_internal_get_resource(request_rec *r, const char *sfn, dmlite_credentials *user, dav_resource **resource) { dav_resource_private *info; int exists, i; const char *p; apr_table_t *query; char replica_key[10]; unsigned nargs; /* Initialize info */ info = apr_pcalloc(r->pool, sizeof(dav_resource_private)); info->stat.extra = dmlite_any_dict_new(); apr_pool_pre_cleanup_register(r->pool, info->stat.extra, (apr_status_t(*)(void*))dmlite_any_dict_free); info->request = r; info->sfn = sfn; info->s_conf = ap_get_module_config(r->server->module_config, &lcgdm_ns_module); info->d_conf = ap_get_module_config(r->per_dir_config, &lcgdm_ns_module); /* User info */ if (user) { info->user = user; } else { if (!(info->user = dav_shared_get_user_credentials(r, info->ctx, info->d_conf->anon_user, info->d_conf->trusted_dns))) return dav_shared_new_error(r, NULL, HTTP_FORBIDDEN, "Can not authenticate the user"); } /* Instantiate the catalog, if not in the connection notes */ info->ctx = (dmlite_context*)apr_table_get(r->connection->notes, "dav_ns_ctx"); if (info->ctx == NULL) { info->ctx = dmlite_context_new(info->s_conf->manager); if (info->ctx == NULL) { return dav_shared_new_error(r, NULL, HTTP_INTERNAL_SERVER_ERROR, "Could not instantiate a context: %s", dmlite_manager_error(info->s_conf->manager)); } apr_pool_pre_cleanup_register(r->connection->pool, info->ctx, (apr_status_t(*)(void*))dmlite_context_free); apr_table_setn(r->connection->notes, "dav_ns_ctx", (char*)info->ctx); if (dmlite_setcredentials(info->ctx, info->user) != 0) return dav_shared_new_error(r, info->ctx, HTTP_FORBIDDEN, "Could not set credentials"); } /* Extract parameters from the query */ query = dav_shared_parse_query(r->pool, r->parsed_uri.query, &nargs); #ifdef WITH_METALINK /* Explicit */ info->metalink = (apr_table_get(query, "metalink") != NULL); /* Through headers maybe? (i.e. aria2c) */ if (!info->metalink && dav_shared_request_accepts(r, "application/metalink+xml")) { info->metalink = 1; } #else info->metalink = 0; #endif info->space_token = apr_table_get(query, "spacetoken"); info->forbidden_str = apr_table_get(query, "forbidden"); info->notfound_str = apr_table_get(query, "notfound"); if ((p = apr_table_get(query, "rid"))) info->r_id = atol(p); else info->r_id = -1; /* Count in advance how many replicas */ info->n_replicas = 0; snprintf(replica_key, sizeof(replica_key), "r%d", info->n_replicas + 1); while(apr_table_get(query, replica_key) != NULL) { ++info->n_replicas; snprintf(replica_key, sizeof(replica_key), "r%d", info->n_replicas + 1); } /* Allocate space */ info->replicas = apr_pcalloc(r->pool, sizeof(char*) * info->n_replicas); info->replicas_ids = apr_pcalloc(r->pool, sizeof(int64_t) * info->n_replicas); /* Go through again :/ */ for (i = 0; i < info->n_replicas; ++i) { const char *field_value; snprintf(replica_key, sizeof(replica_key), "r%d", i + 1); field_value = apr_table_get(query, replica_key); info->replicas[i] = apr_pcalloc(r->pool, sizeof(char) * PATH_MAX); if (sscanf(field_value, "%"PRId64",%s", &info->replicas_ids[i], info->replicas[i]) != 2) { return dav_shared_new_error(r, NULL, HTTP_BAD_REQUEST, "Replica parameters malformed"); } } /* Stat */ switch (dmlite_statx(info->ctx, info->sfn, &(info->stat))) { /* We are good */ case 0: exists = 1; break; /* Access denied */ case DM_FORBIDDEN: /* If this is not a HEAD or a GET (both are M_GET), just fail, * but keep going otherwise */ if (r->method_number != M_GET) return dav_shared_new_error(r, info->ctx, 0, "Access forbidden for %s on %s", info->sfn, r->method); case DM_NO_SUCH_FILE: exists = 0; /* When creating a file, break here */ if (r->method_number == M_PUT || r->method_number == M_MKCOL || r->method_number == M_MOVE) break; /* Now, fall-back to the next replica in the list, if any */ 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, info->r_id); if (info->redirect != NULL) { apr_table_set(r->headers_out, "Location", info->redirect); return dav_new_error(r->pool, HTTP_MOVED_TEMPORARILY, 0, info->redirect); } /* We can't :(, so go to default */ default: return dav_shared_new_error(r, info->ctx, 0, "Can not stat %s", info->sfn); } /* Create and return resource */ *resource = apr_pcalloc(r->pool, sizeof(dav_resource)); (*resource)->type = DAV_RESOURCE_TYPE_REGULAR; (*resource)->exists = exists; (*resource)->collection = ((info->stat.stat.st_mode & S_IFDIR) != 0); (*resource)->uri = sfn; (*resource)->info = info; (*resource)->hooks = &dav_ns_hooks_repository; (*resource)->pool = r->pool; if (exists) ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Resource for %s (%s) found (dir=%d)", (*resource)->uri, (*resource)->info->sfn, (*resource)->collection); else ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "NULL resource for %s (%s) created", (*resource)->uri, (*resource)->info->sfn); return NULL; }