doc/warehouse_api_final.md | 6 -
notes.txt | 192 ---------------------------------------------
rest.c | 52 +++++++++++-
t/basic | 32 +++++--
template.c | 4
5 files changed, 79 insertions(+), 207 deletions(-)
New commits:
commit b57b085b8f106c8f5f187213809b44db7cf92de1
Author: Jim Meyering <meyering(a)redhat.com>
Date: Thu Mar 10 20:11:13 2011 +0100
maint: remove notes.txt
* notes.txt: Remove file. It contains some outdated (invalid)
examples. The authoritative documentation is in
doc/warehouse_api_final.md
diff --git a/notes.txt b/notes.txt
deleted file mode 100644
index 92e4646..0000000
--- a/notes.txt
+++ /dev/null
@@ -1,192 +0,0 @@
-Commands:
-
- GET /
- list top-level objects
-
- POST /_new/bucket
- create bucket with attributes
-
- GET /_providers
- list providers
-
- POST /_providers/_new/provider
- create new provider with info
-
- GET /_providers/provider
- show provider information (requires token)
-
- POST /_providers/provider
- set provider information (requires/token)
-
- GET /bucket
- list bucket contents
-
- GET /bucket?query=xxx
- query bucket contents
-
- DELETE /bucket
- delete bucket (must be empty)
-
- POST /bucket/_new/object
- create object with attributes
-
- GET /bucket/object
- get body/attr* list
-
- GET /bucket/object/body
- get object body
-
- PUT /bucket/object/body
- put object body
-
- POST /bucket/object op=push
- trigger re-replication
-
- POST /bucket/object op=pull depot=xxx
- trigger reverse replication
-
- POST /bucket/object op-check depot=xxx
- check availability
-
- DELETE /bucket/object
- delete object
-
- GET /bucket/object/attrs
- get all attributes
-
- POST /bucket/object/attrs
- set multiple attributes
-
- GET /bucket/object/attr_X
- get attribute X
-
- PUT /bucket/object/attr_X
- set attribute X
-
- DELETE /bucket/object/attr_X
- delete attribute X
-
-Formats:
-
- JSON top-level list
- [
- {
- "type": "bucket_factory",
- "path": ".../_new"
- },
- {
- "type": "provider_list",
- "path": ".../_providers"
- },
- {
- "type": "bucket",
- "name": "bucketA",
- "path": ".../bucketA"
- },
- {
- "type": "bucket",
- "name": "bucketB",
- "path": ".../bucketB"
- }
- ]
-
- JSON provider list
- [
- {
- "name": "my primary",
- "type": "cf",
- "host": "swift.usersys.redhat.com",
- "port": 8080,
- "username": "my_cf_username",
- "password": "my_cf_password"
- },
- {
- "name": "my secondary",
- "type": "s3",
- "host": "s3.amazonaws.com",
- "port": 80,
- "username": "my_aws_key",
- "password": "my_aws_secret"
- }
- }
-
- JSON bucket-level list
- [
- {
- "type": "object_factory",
- "path": ".../bucket/_new"
- },
- {
- "type": "object",
- "name": "objectC",
- "path": ".../bucketA/objectC"
- },
- {
- "type": "object",
- "name": "objectD",
- "path": ".../bucketA/objectD"
- }
- ]
-
- JSON object-level list
- [
- {
- "type": "body",
- "path": ".../bucketA/objectC/body"
- },
- {
- "type": "multi_attributes",
- "path": ".../bucketA/objectC/attrs"
- },
- {
- "type": "single_attribute",
- "name": "abc",
- "path": ".../bucketA/objectC/attr_abc"
- }
- {
- "type": "single_attribute",
- "name": "xyz",
- "path": ".../bucketA/objectC/attr_xyz"
- }
- ]
-
-
-To Do - priority (1 highest) work (5 largest) desc:
- 1 1 policy inheritance
- 1 2 delete metadata as well as data
- 1 3 re-replicate on policy change (single object)
- 2 2 manual re-replication trigger
- 2 1 re-replicate on *any* tag change
- 2 3 replication-complete API
- 2 5 basic cred-management API
- 2 3 content types
- --- done
- 2 1 start own MongoDB
- 2 2 reverse-replication API
- 2 4 link-following syntax
- 2 5 reconcile dispatch with commands/format above
- 3 5 fully modular FS/S3/CF driver structure
- 3 5 VMWare back end
- 3 5 EBS back end
- 3 5 RHEV back end (dependency on Ayal)
- * Mark McLoughlin / Eoghan Glynn / rhevm-api
- 3 5 start own Hail
- 3 5 fully dynamic config
- 3 3 fix string handling (eliminate strtok)
- 3 4 re-replicate on policy change (default)
- 3 4 writes proxied upstream
- 4 1 direct-copy API (PUT with special header?)
- 4 2 use MongoDB C driver now that it's supported
- 4 3 chunked encoding
- 4 3 statistics/usage API
- 4 3 enhanced query syntax (limits)
- 4 4 optimize re-replication (check current locs)
- 4 5 dcloud-obj back end
- 4 5 immediate inline replication
- 4 5 generate MongoDB queries from ours
- 4 5 auth
- 5 2 deletes proxied upstream
- 5 3 cache control (TTL?)
- 5 5 replicated DB
- partial-object reads
- partial-object writes?
commit b6672826972980fb440a0fd6ea158b6845ede12f
Author: Jim Meyering <meyering(a)redhat.com>
Date: Thu Mar 10 19:51:45 2011 +0100
adjust code, doc and tests to use ".../_attrs", not ".../attrs"
The latter never worked. Now, GET with the former does.
* doc/warehouse_api_final.md: s,/attrs,/_attrs,
* t/basic: Likewise.
* template.c (xml_obj_header, json_obj_header): Likewise.
diff --git a/doc/warehouse_api_final.md b/doc/warehouse_api_final.md
index dd7ea57..31adfe9 100644
--- a/doc/warehouse_api_final.md
+++ b/doc/warehouse_api_final.md
@@ -140,7 +140,7 @@ elements as shown here:
$ curl
http://fserver-1:9090/my_bucket/file1
<object>
<object_body path="http://fserver-1:9090/my_bucket/file1/body"/>
- <object_attr_list
path="http://fserver-1:9090/my_bucket/file1/attrs"/>
+ <object_attr_list
path="http://fserver-1:9090/my_bucket/file1/_attrs"/>
<object_attr name="xyz"
path="http://fserver-1:9090/my_bucket/file1/attr_xyz"/>
</object>
@@ -149,7 +149,7 @@ and can have any HTTP/MIME type. The attribute-list element
can be used to fetch or set multiple attributes - including values
- at once. To fetch:
- $ curl
http://fserver-1:9090/my_bucket/file1/attrs
+ $ curl
http://fserver-1:9090/my_bucket/file1/_attrs
<attributes>
<attribute name="color">blue</attribute>
<attribute name="flavor">lemon</attribute>
@@ -158,7 +158,7 @@ can be used to fetch or set multiple attributes - including values
To set both of these attributes at once:
$ curl -d color="blue" -d flavor="lemon" \
-
http://fserver-1:9090/my_bucket/file1/attrs
+
http://fserver-1:9090/my_bucket/file1/_attrs
Single-attribute operations are also supported. To fetch a
single attribute:
diff --git a/t/basic b/t/basic
index b902adf..e524909 100644
--- a/t/basic
+++ b/t/basic
@@ -175,7 +175,7 @@ test "$(curl $bucket/attr_post/size)" = big || fail=1
cat <<EOF > exp-attr
<object>
<object_body path="$bucket/attr_post/body"/>
- <object_attr_list path="$bucket/attr_post/attrs"/>
+ <object_attr_list path="$bucket/attr_post/_attrs"/>
<object_attr name="shape"
path="$bucket/attr_post/attr_shape"/>
<object_attr name="size" path="$bucket/attr_post/attr_size"/>
</object>
diff --git a/template.c b/template.c
index 019dac6..4e2f315 100644
--- a/template.c
+++ b/template.c
@@ -75,7 +75,7 @@ static const char xml_list_footer[] = "\
static const char xml_obj_header[] = "\
<object>\n\
<object_body path=\"http://%s/%s/%s/body\"/>\n\
- <object_attr_list path=\"http://%s/%s/%s/attrs\"/>\
+ <object_attr_list path=\"http://%s/%s/%s/_attrs\"/>\
";
static const char xml_obj_entry[] = "\
@@ -166,7 +166,7 @@ static const char json_list_footer[] = "\
static char json_obj_header[] = "\
{\n\
\"object_body\": \"http://%s/%s/%s/body\"\n\
- \"object_attr_list\": \"http://%s/%s/%s/attrs\"\
+ \"object_attr_list\": \"http://%s/%s/%s/_attrs\"\
";
static char json_obj_entry[] = "\
commit 1d05af0593621f31e8cfce1472a6e81d58d47009
Author: Jim Meyering <meyering(a)redhat.com>
Date: Thu Mar 10 17:08:24 2011 +0100
allow "GET
http://host/bucket/object/_attrs" to list attributes
* rest.c (URL_LIST_ATTRS): New enum member.
(reserved_attr): Add "_attrs".
(show_parts): Add forward declaration.
(proxy_list_attrs): New function.
(show_parts): Move a decl down.
(my_rules): Add a new entry to handle GET + URL_LIST_ATTRS.
(parse_url): Parse a "BUCKET/OBJECT/_attrs" URL as URL_LIST_ATTRS.
* t/basic: Automatically compare hard-coded list of reserved
attribute names and the list in rest.c, rather than relying
on a FIXME comment to help us keep things in sync.
Test new GET
http://host/bucket/object/_attrs as well as
legacy (now declared to be "deprecated") op=parts interface.
diff --git a/rest.c b/rest.c
index 4681871..84757e9 100644
--- a/rest.c
+++ b/rest.c
@@ -75,7 +75,8 @@ enum { CB_BLOCK_SIZE = 64 * 1024 };
typedef enum {
URL_ROOT=0, URL_BUCKET, URL_OBJECT, URL_ATTR, URL_INVAL,
- URL_QUERY, URL_PROVLIST, URL_PROVIDER, URL_PROVIDER_SET_PRIMARY
+ URL_QUERY, URL_PROVLIST, URL_PROVIDER, URL_PROVIDER_SET_PRIMARY,
+ URL_LIST_ATTRS
} url_type;
typedef struct {
@@ -88,7 +89,7 @@ static unsigned short my_port = MY_PORT;
char *cfg_file = NULL;
static const char *const (reserved_name[]) = {"_default", "_new",
"_policy", "_query", NULL};
-static const char *const (reserved_attr[]) = {"_bucket", "_date",
"_etag", "_key", "_loc", "_size", NULL};
+static const char *const (reserved_attr[]) = {"_attrs", "_bucket",
"_date", "_etag", "_key", "_loc",
"_size", NULL};
static const char *const (reserved_bucket_name[]) = {"_new",
"_providers", NULL};
static int
@@ -521,6 +522,47 @@ proxy_put_data (void *cctx, struct MHD_Connection *conn, const char
*url,
return MHD_YES;
}
+static int show_parts (struct MHD_Connection *conn, my_state *ms);
+
+static int
+proxy_list_attrs (void *cctx, struct MHD_Connection *conn, const char *url,
+ const char *method, const char *version, const char *data,
+ size_t *data_size, void **rctx)
+{
+ (void)cctx;
+ (void)method;
+ (void)version;
+
+ my_state *ms = *rctx;
+ if (ms->state == MS_NEW) {
+ ms->state = MS_NORMAL;
+ }
+ else if (*data_size) {
+ MHD_post_process(ms->post,data,*data_size);
+ *data_size = 0;
+ }
+ else {
+ int rc = show_parts(conn,ms);
+ if (rc != MHD_HTTP_PROCESSING) {
+ /*
+ * MHD_HTTP_PROCESSING is a special response that
+ * means a request-specific routine (e.g. show_parts)
+ * created its own response. Therefore we shouldn't.
+ */
+ struct MHD_Response *resp
+ = MHD_create_response_from_data(0,NULL, MHD_NO,MHD_NO);
+ if (!resp) {
+ fprintf(stderr,"MHD_crfd failed\n");
+ return MHD_NO;
+ }
+ MHD_queue_response(conn,rc,resp);
+ MHD_destroy_response(resp);
+ }
+ }
+
+ return MHD_YES;
+}
+
static int
proxy_get_attr (void *cctx, struct MHD_Connection *conn, const char *url,
const char *method, const char *version, const char *data,
@@ -1400,13 +1442,13 @@ parts_callback (void *ctx, uint64_t pos, char *buf, size_t max)
static int
show_parts (struct MHD_Connection *conn, my_state *ms)
{
- struct MHD_Response *resp;
ms->aquery = meta_get_attrs(ms->bucket,ms->key);
if (!ms->aquery) {
return MHD_HTTP_NOT_FOUND;
}
+ struct MHD_Response *resp;
resp = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN,
CB_BLOCK_SIZE, parts_callback, ms, simple_closer);
if (!resp) {
@@ -1981,6 +2023,8 @@ static const rule my_rules[] = {
"GET", URL_OBJECT, proxy_get_data },
{ /* get attribute data */
"GET", URL_ATTR, proxy_get_attr },
+ { /* list an object's attributes */
+ "GET", URL_LIST_ATTRS, proxy_list_attrs },
{ /* put object data */
"PUT", URL_OBJECT, proxy_put_data },
{ /* put attribute data */
@@ -2065,6 +2109,8 @@ parse_url (const char *url, my_state *ms)
&& !strcmp (parts[URL_BUCKET], "_providers")
&& !strcmp (parts[URL_ATTR], "_primary"))
eindex = URL_PROVIDER_SET_PRIMARY;
+ else if (eindex == URL_ATTR && !strcmp (parts[URL_ATTR], "_attrs"))
+ eindex = URL_LIST_ATTRS;
DPRINTF("parse_url: %d: %s %s %s", eindex, parts[URL_BUCKET],
parts[URL_OBJECT], parts[URL_ATTR]);
diff --git a/t/basic b/t/basic
index 82005e2..b902adf 100644
--- a/t/basic
+++ b/t/basic
@@ -172,8 +172,6 @@ curl -d _key=attr_post -d shape=round -d size=big $bucket || fail=1
test "$(curl $bucket/attr_post/shape)" = round || fail=1
test "$(curl $bucket/attr_post/size)" = big || fail=1
-# Print all attributes of an object:
-curl -d op=parts $bucket/attr_post > out-attr || fail=1
cat <<EOF > exp-attr
<object>
<object_body path="$bucket/attr_post/body"/>
@@ -182,7 +180,12 @@ cat <<EOF > exp-attr
<object_attr name="size" path="$bucket/attr_post/attr_size"/>
</object>
EOF
+# Print all attributes of an object:
+curl $bucket/attr_post/_attrs > out-attr || fail=1
compare out-attr exp-attr || fail=1
+# Do the same thing using the old, deprecated mechanism:
+curl -d op=parts $bucket/attr_post > out-attr-deprecated || fail=1
+compare out-attr-deprecated exp-attr || fail=1
# Ensure that an attempt to add reserved object name fails.
# FIXME: keep this list in sync with the one in rest.c:
@@ -197,12 +200,27 @@ for obj_name in _default _new _policy _query; do
grep " $exp\$" bad_oname.err || fail=1
done
+# Keep this list of reserved words in sync with the one in rest.c:
+attr_words='_attrs _bucket _date _etag _key _loc _size'
+
+actual=$(grep '^static.*reserved_attr' "$abs_top_srcdir/rest.c" \
+ |perl -pe 's/.*?"//;s/", NULL.*//;s/", "/ /g')
+case $attr_words in
+ "$actual") ;;
+ *) fail_ reserved attribute mismatch;;
+esac
+
# Ensure that an attempt to add each reserved attribute fails.
-# FIXME: keep this list in sync with the one in rest.c:
-# grep '^static.*reserved_attr' rest.c
-for attr in _bucket _key _date _etag _loc _size; do
+for attr in $attr_words; do
+ case $attr in
+ # _attrs is defined only for GET, so evokes 404 rather than 400
+ _attrs) exp=404;;
+ *) exp=400;;
+ esac
+
printf whatever | curl -f -T - $bucket/rsvd_attr/$attr 2> bad_attr.err
- grep ' 400$' bad_attr.err || fail=1
+ grep " $exp$" bad_attr.err || { echo got this:; cat bad_attr.err;
+ fail_ "expected $exp"; }
done
# Ensure that an attempt to create a bucket with a reserved name fails.