| 1 | # Copyright (C) 2007 AG Projects. |
|---|
| 2 | # |
|---|
| 3 | |
|---|
| 4 | """XCAP resources module""" |
|---|
| 5 | |
|---|
| 6 | from application import log |
|---|
| 7 | |
|---|
| 8 | from twisted.web2 import http, resource, responsecode |
|---|
| 9 | from twisted.web2.http_headers import ETag, MimeType |
|---|
| 10 | from twisted.web2.static import MetaDataMixin |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | class XCAPResource(resource.Resource, resource.LeafResource, MetaDataMixin): |
|---|
| 14 | |
|---|
| 15 | def __init__(self, xcap_uri, application): |
|---|
| 16 | self.xcap_uri = xcap_uri |
|---|
| 17 | self.application = application |
|---|
| 18 | self.e_tag = None |
|---|
| 19 | |
|---|
| 20 | def checkPreconditions(self, request): |
|---|
| 21 | ## don't let renderHTTP to automatically check preconditions, we'll do this ourselves |
|---|
| 22 | return None |
|---|
| 23 | |
|---|
| 24 | def checkEtag(self, request, etag): |
|---|
| 25 | http.checkPreconditions(request, etag=ETag(etag)) |
|---|
| 26 | |
|---|
| 27 | def renderHTTP(self, request): |
|---|
| 28 | d = resource.Resource.renderHTTP(self, request) |
|---|
| 29 | d.addCallback(self.sendResponse) |
|---|
| 30 | return d |
|---|
| 31 | |
|---|
| 32 | def setHeaders(self, response): |
|---|
| 33 | ## Don't provide additional resource information to error responses, |
|---|
| 34 | ## this is already done by the responses in the errors module |
|---|
| 35 | if response.code < 400: |
|---|
| 36 | for (header, value) in ( |
|---|
| 37 | ("etag", self.etag()), |
|---|
| 38 | ("content-type", self.contentType()) |
|---|
| 39 | ): |
|---|
| 40 | if value is not None: |
|---|
| 41 | response.headers.setHeader(header, value) |
|---|
| 42 | return response |
|---|
| 43 | |
|---|
| 44 | def sendResponse(self, response): |
|---|
| 45 | if response.etag: |
|---|
| 46 | self.e_tag = ETag(response.etag) |
|---|
| 47 | response = http.Response(response.code, stream=response.data) |
|---|
| 48 | return self.setHeaders(response) |
|---|
| 49 | |
|---|
| 50 | def etag(self): |
|---|
| 51 | return self.e_tag or None |
|---|
| 52 | |
|---|
| 53 | |
|---|
| 54 | class XCAPDocument(XCAPResource): |
|---|
| 55 | |
|---|
| 56 | def http_GET(self, request): |
|---|
| 57 | d = self.application.get_document(self.xcap_uri, lambda e: self.checkEtag(request, e)) |
|---|
| 58 | return d |
|---|
| 59 | |
|---|
| 60 | def http_PUT(self, request): |
|---|
| 61 | application = self.application |
|---|
| 62 | document = request.attachment |
|---|
| 63 | return application.put_document(self.xcap_uri, document, lambda e: self.checkEtag(request, e)) |
|---|
| 64 | |
|---|
| 65 | def http_DELETE(self, request): |
|---|
| 66 | d = self.application.delete_document(self.xcap_uri, lambda e: self.checkEtag(request, e)) |
|---|
| 67 | return d |
|---|
| 68 | |
|---|
| 69 | def contentType(self): |
|---|
| 70 | return MimeType.fromString(self.application.mime_type) |
|---|
| 71 | |
|---|
| 72 | |
|---|
| 73 | class XCAPElement(XCAPResource): |
|---|
| 74 | |
|---|
| 75 | content_type = MimeType.fromString("application/xcap-el+xml") |
|---|
| 76 | |
|---|
| 77 | def http_GET(self, request): |
|---|
| 78 | d = self.application.get_element(self.xcap_uri, lambda e: self.checkEtag(request, e)) |
|---|
| 79 | return d |
|---|
| 80 | |
|---|
| 81 | def http_DELETE(self, request): |
|---|
| 82 | d = self.application.delete_element(self.xcap_uri, lambda e: self.checkEtag(request, e)) |
|---|
| 83 | return d |
|---|
| 84 | |
|---|
| 85 | def http_PUT(self, request): |
|---|
| 86 | content_type = request.headers.getHeader('content-type') |
|---|
| 87 | if not content_type or content_type != self.content_type: |
|---|
| 88 | raise http.HTTPError(responsecode.UNSUPPORTED_MEDIA_TYPE) |
|---|
| 89 | element = request.attachment |
|---|
| 90 | d = self.application.put_element(self.xcap_uri, element, lambda e: self.checkEtag(request, e)) |
|---|
| 91 | return d |
|---|
| 92 | |
|---|
| 93 | def contentType(self): |
|---|
| 94 | return self.content_type |
|---|
| 95 | |
|---|
| 96 | class XCAPAttribute(XCAPResource): |
|---|
| 97 | |
|---|
| 98 | content_type = MimeType.fromString("application/xcap-att+xml") |
|---|
| 99 | |
|---|
| 100 | def contentType(self): |
|---|
| 101 | return self.content_type |
|---|
| 102 | |
|---|
| 103 | def http_GET(self, request): |
|---|
| 104 | d = self.application.get_attribute(self.xcap_uri, lambda e: self.checkEtag(request, e)) |
|---|
| 105 | return d |
|---|
| 106 | |
|---|
| 107 | def http_DELETE(self, request): |
|---|
| 108 | d = self.application.delete_attribute(self.xcap_uri, lambda e: self.checkEtag(request, e)) |
|---|
| 109 | return d |
|---|
| 110 | |
|---|
| 111 | def http_PUT(self, request): |
|---|
| 112 | content_type = request.headers.getHeader('content-type') |
|---|
| 113 | if not content_type or content_type != self.content_type: |
|---|
| 114 | raise http.HTTPError(responsecode.UNSUPPORTED_MEDIA_TYPE) |
|---|
| 115 | attribute = request.attachment |
|---|
| 116 | d = self.application.put_attribute(self.xcap_uri, attribute, lambda e: self.checkEtag(request, e)) |
|---|
| 117 | return d |
|---|
| 118 | |
|---|
| 119 | |
|---|
| 120 | class XCAPNamespaceBinding(XCAPResource): |
|---|
| 121 | |
|---|
| 122 | content_type = MimeType.fromString("application/xcap-ns+xml") |
|---|
| 123 | |
|---|
| 124 | def contentType(self): |
|---|
| 125 | return self.content_type |
|---|
| 126 | |
|---|
| 127 | def http_GET(self, request): |
|---|
| 128 | d = self.application.get_ns_bindings(self.xcap_uri, lambda e: self.checkEtag(request, e)) |
|---|
| 129 | return d |
|---|