Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added cdmi Request parser object and created tests for it.
Also added the CDMI protocol specfile.
- Loading branch information
1 parent
58ff3d0
commit ff71b0c
Showing
5 changed files
with
355 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.pyc |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
#!/usr/bin/env python | ||
# Koen Bollen <meneer@koenbollen.nl> | ||
# 2010 GPL | ||
|
||
SPECIFICATION_VERSION = 1.0 | ||
|
||
httpstatuscodes = [ | ||
( 200, "OK", | ||
"Resource retrieved successfully" ), | ||
( 201, "Created", | ||
"Resource created successfully" ), | ||
( 202, "Accepted", | ||
"Long running operation accepted for processing" ), | ||
( 204, "No Content", | ||
"Operation successful, no data" ), | ||
( 400, "Bad Request", | ||
"Missing or invalid request contents" ), | ||
( 401, "Unauthorized", | ||
"Invalid authentication/authorization credentials" ), | ||
( 403, "Forbidden", | ||
"This user is not allowed to perform this request" ), | ||
( 404, "Not Found", | ||
"Requested resource not found" ), | ||
( 405, "Method Not Allowed", | ||
"Requested HTTP verb not allowed on this resource" ), | ||
( 406, "Not Acceptable", | ||
"No content type can be produced at this URI that matches the request" ), | ||
( 409, "Conflict", | ||
"The operation conflicts with a non-CDMI access protocol lock, " | ||
+ "or could cause a state transition error on the server." ), | ||
( 500, "Internal Server Error", | ||
"An unexpected vendor specific error" ), | ||
( 501, "Not Implemented", | ||
"A CDMI operation or metadata value was attempted that is not implemented.") | ||
] | ||
|
||
mimetypes = { | ||
'object': "application/vnd.org.snia.cdmi.object+json", | ||
'container': "application/vnd.org.snia.cdmi.container+json", | ||
'dataobject': "application/vnd.org.snia.cdmi.dataobject+json", | ||
'domain': "application/vnd.org.snia.cdmi.domain+json", | ||
'queue': "application/vnd.org.snia.cdmi.queue+json", | ||
'capabilities': "application/vnd.org.snia.cdmi.capabilities+json", | ||
} | ||
|
||
class CDMIError( Exception ): | ||
pass | ||
|
||
class CDMIProtocolError( CDMIError ): | ||
def __init__(self, message, cause ): | ||
self.message = message | ||
self.cause = cause | ||
|
||
def __str__(self ): | ||
return "%s: %r" % (self.message, self.cause) | ||
|
||
def __repr__(self ): | ||
return "<CDMIProtocolError %s>" % (str(self)) | ||
|
||
class Request( object ): | ||
|
||
def __init__(self, method, path, headers ): | ||
|
||
self.method = method.lower() | ||
self.path = path.strip() | ||
self.headers = headers | ||
self.cdmi = None | ||
self.objecttype = "unknown" | ||
self.source = None | ||
self.json = None | ||
|
||
self.__validate() | ||
self.__parse() | ||
|
||
def __validate(self ): | ||
if self.method not in ("get", "post", "put", "delete"): | ||
raise CDMIProtocolError( "invalid method:", self.method ) | ||
if self.path[0] != '/': | ||
raise CDMIProtocolError( "invalid path", self.path ) | ||
|
||
def __parse(self ): | ||
h = self.headers | ||
spec = h.get('X-CDMI-Specification-Version') | ||
self.cdmi = spec is not None | ||
if self.cdmi: | ||
|
||
try: | ||
if float(spec) < SPECIFICATION_VERSION: | ||
raise ValueError | ||
except ValueError: | ||
raise CDMIProtocolError( "incorrect version", spec ) | ||
|
||
try: | ||
accept = h['Accept'] | ||
contenttype = h['Content-Type'] | ||
except KeyError, e: | ||
# One exception, a GET request without a type: | ||
if not (e.args[0].lower() == "accept" and self.method=="get"): | ||
raise CDMIProtocolError( "missing header", str(e) ) | ||
accept = None | ||
|
||
for objecttype, mime in mimetypes.items(): | ||
if accept == contenttype == mime: | ||
self.objecttype = objecttype | ||
break | ||
if self.method == "get" and accept == mime: | ||
self.objecttype = objecttype | ||
break | ||
if self.objecttype == "object": | ||
self.objecttype = "unknown" | ||
|
||
self.accept = accept | ||
self.contenttype = contenttype | ||
|
||
else: | ||
self.accept = None | ||
self.contenttype = h.get('Content-Type') | ||
if self.method in ("put","post"): | ||
if self.contenttype: | ||
self.objecttype = "dataobject" | ||
else: | ||
self.objecttype = "container" | ||
else: | ||
self.objecttype = "unknown" | ||
|
||
p = self.path | ||
self.fields = {} | ||
if "?" in self.path: | ||
self.path, fstr = self.path.split( "?", 1 ) | ||
fields = [(f.split(":", 1)+[None])[:2] for f in fstr.split(";")] | ||
for k,v in fields: | ||
if v: | ||
v = v.strip() | ||
self.fields[k.strip().lower()] = v | ||
|
||
def __repr__(self ): | ||
tmpl = "<cdmi request: {cdmi} {method} a {objecttype}: '{path}'>" | ||
values = vars(self) | ||
values['cdmi'] = self.cdmi and "cdmi" or "non-cdmi" | ||
return tmpl.format( **values ) | ||
|
||
def read(self, fp ): | ||
pass | ||
|
||
# vim: expandtab shiftwidth=4 softtabstop=4 textwidth=79: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#!/usr/bin/env python | ||
# Koen Bollen <meneer koenbollen nl> | ||
# 2010 GPL | ||
|
||
import os | ||
import yaml | ||
|
||
import cdmi | ||
|
||
def main(): | ||
path = os.path.join( os.path.dirname(__file__), "requests.yaml" ) | ||
requests = yaml.load( open( path ) ) | ||
for req in requests: | ||
print req['description'] | ||
|
||
headers = req.get( "headers", {} ) | ||
headers['Host'] = "localhost" | ||
res = cdmi.Request( req['method'], req['path'], headers ) | ||
print res, res.fields | ||
|
||
if __name__ == "__main__": | ||
main() | ||
|
||
# vim: expandtab shiftwidth=4 softtabstop=4 textwidth=79: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
--- | ||
- description: Create a Container (CDMI Content Type) | ||
method: PUT | ||
path: /mydata | ||
headers: | ||
Accept: application/vnd.org.snia.cdmi.container+json | ||
Content-Type: application/vnd.org.snia.cdmi.container+json | ||
X-CDMI-Specification-Version: 1.0 | ||
data: | | ||
{ | ||
"metadata": { | ||
} | ||
} | ||
response: 201 | ||
|
||
- description: Create a Container (Non-CDMI Content Type) | ||
method: PUT | ||
path: /mydata | ||
response: 201 | ||
|
||
- description: Read a Container Object (CDMI Content Type) | ||
method: GET | ||
path: /mydata | ||
headers: | ||
Accept: application/vnd.org.snia.cdmi.container+json | ||
Content-Type: application/vnd.org.snia.cdmi.object+json | ||
X-CDMI-Specification-Version: 1.0 | ||
response: 200 | ||
|
||
- description: Read a Container Object (CDMI Content Type) | ||
method: GET | ||
path: /mydata?children:0-42 | ||
headers: | ||
Accept: application/vnd.org.snia.cdmi.container+json | ||
Content-Type: application/vnd.org.snia.cdmi.object+json | ||
X-CDMI-Specification-Version: 1.0 | ||
response: 200 | ||
|
||
- description: Read a Container Object (Non-CDMI Content Type) | ||
method: GET | ||
path: /mydata?parentURI | ||
response: 200 | ||
|
||
- description: Update a Container (CDMI Content Type) | ||
method: PUT | ||
path: /mydata | ||
headers: | ||
Accept: application/vnd.org.snia.cdmi.container+json | ||
Content-Type: application/vnd.org.snia.cdmi.container+json | ||
X-CDMI-Specification-Version: 1.0 | ||
data: | | ||
{ | ||
"metadata": { | ||
'creator': "Koen Bollen", | ||
'tags': "test" | ||
} | ||
} | ||
response: 200 | ||
|
||
- description: Delete a Container Object (CDMI Content Type) | ||
method: DELETE | ||
path: /mydata | ||
headers: | ||
Accept: application/vnd.org.snia.cdmi.container+json | ||
Content-Type: application/vnd.org.snia.cdmi.container+json | ||
X-CDMI-Specification-Version: 1.0 | ||
response: 200 | ||
|
||
- description: Delete a Container Object (Non-CDMI Content Type) | ||
method: DELETE | ||
path: /mydata | ||
response: 200 | ||
|
||
- description: Create a New Data Object (CDMI Content Type) | ||
method: POST | ||
path: /mydata/ | ||
headers: | ||
Accept: application/vnd.org.snia.cdmi.dataobject+json | ||
Content-Type: application/vnd.org.snia.cdmi.dataobject+json | ||
X-CDMI-Specification-Version: 1.0 | ||
data: | | ||
{ | ||
"mimetype" : "text/plain", | ||
"metadata" : { | ||
}, | ||
"value" : "The cake is a lie!" | ||
} | ||
response: 201 | ||
|
||
- description: Create a New Data Object (Non-CDMI Content Type) | ||
method: POST | ||
path: /mydata/ | ||
headers: | ||
Content-Type: text/plain | ||
Content-Length: 15 | ||
data: Koen was hier!! | ||
response: 201 | ||
|
||
|
||
- description: Create a Data Object (CDMI Content Type) | ||
method: PUT | ||
path: /mydata/hello.txt | ||
headers: | ||
Accept: application/vnd.org.snia.cdmi.dataobject+json | ||
Content-Type: application/vnd.org.snia.cdmi.dataobject+json | ||
X-CDMI-Specification-Version: 1.0 | ||
data: | | ||
{ | ||
"mimetype" : "text/plain", | ||
"metadata" : { | ||
}, | ||
"value" : "Hello, world!!\n" | ||
} | ||
response: 201 | ||
|
||
- description: Create a Data Object (Non-CDMI Content Type) | ||
method: PUT | ||
path: /mydata/hello.txt | ||
headers: | ||
Content-Type: text/plain | ||
Content-Length: 15 | ||
data: Hello, world!!\n | ||
response: 201 | ||
|
||
- description: Read a Data Object (CDMI Content Type) | ||
method: GET | ||
path: /mydata/hello.txt | ||
headers: | ||
Accept: application/vnd.org.snia.cdmi.dataobject+json | ||
Content-Type: application/vnd.org.snia.cdmi.object+json | ||
X-CDMI-Specification-Version: 1.0 | ||
response: 200 | ||
|
||
- description: Read a Data Object (Non-CDMI Content Type) | ||
method: GET | ||
path: /mydata/hello.txt | ||
response: 200 | ||
|
||
- description: Read a Data Object Fields (Non-CDMI Content Type) | ||
method: GET | ||
path: /mydata/hello.txt?objectID;metadata | ||
response: 200 | ||
|
||
- description: Update a Data Object (CDMI Content Type) | ||
method: PUT | ||
path: /mydata/hello.txt | ||
headers: | ||
Accept: application/vnd.org.snia.cdmi.dataobject+json | ||
Content-Type: application/vnd.org.snia.cdmi.dataobject+json | ||
X-CDMI-Specification-Version: 1.0 | ||
data: | | ||
{ | ||
"mimetype" : "text/plain", | ||
"metadata" : { | ||
}, | ||
"value" : "new value.." | ||
} | ||
response: 201 | ||
|
||
- description: Update a Data Object (Non-CDMI Content Type) | ||
method: PUT | ||
path: /mydata/hello.txt | ||
headers: | ||
Content-Type: text/plain | ||
Content-Length: 5 | ||
data: sup?\n | ||
response: 201 | ||
|
||
- description: Delete a Data Object (CDMI Content Type) | ||
method: DELETE | ||
path: /mydata/hello.txt | ||
headers: | ||
Accept: application/vnd.org.snia.cdmi.dataobject+json | ||
Content-Type: application/vnd.org.snia.cdmi.dataobject+json | ||
X-CDMI-Specification-Version: 1.0 | ||
response: 200 | ||
|
||
- description: Delete a Data Object (Non-CDMI Content Type) | ||
method: DELETE | ||
path: /mydata/hello.txt | ||
response: 200 | ||
|