Source code for pOCCI.render_http

import re

import occi

from render_base import Renderer
from render_text import *


[docs]class HTTPHeadersRenderer(TextRenderer): """HTTP Headers OCCI Renderer RFC 7230 http://www.ietf.org/rfc/rfc7230.txt. Empty string is always returned as body during rendering. Beware of HTTP Headers size limitations. It is better to not use 'text/occi' mimetype for transfering OCCI Category Collection. """ reHeaderChunk = re.compile(r'(?P<chunk>((?P<quoted>"([^"\\]|\\.)*")|(?P<term>[^,"\\]+))*)(?P<sep>\s*,\s*)?')
[docs] def render_category(self, category): """Render OCCI Category :param occi.Category category: OCCI Category object :return: render result :rtype: [string, string[]] """ return ['', ['Category: ' + text_category(category)]]
[docs] def render_categories(self, categories): """Render OCCI Category collection :param occi.Category category[]: OCCI Category array :return: render result :rtype: [string, string[]] """ if not categories: return ['', []] res = [] for category in categories: res.append(text_category(category)) return ['', ['Category: ' + ','.join(res)]]
[docs] def render_attributes(self, attributes): """Render Attributes :param occi.Attribute attribute[]: OCCI Attribute object :return: render result :rtype: string[] """ if not attributes: return [] s = [] for attribute in attributes: s.append(text_attribute_repr(attribute)) return ['X-OCCI-Attribute: ' + ','.join(s)]
[docs] def render_locations(self, locations): """ Render Locations :param string location: location URI :return: render result :rtype: [string, string[]] """ return ['', ['X-OCCI-Location: ' + ','.join(locations)]]
[docs] def render_resource(self, categories, links=None, attributes=None): """Render OCCI Resource instance :param occi.Category category: OCCI Category object :param occi.Link links[]: OCCI Link array :param occi.Attribute attributes[]: OCCI Attribute array :return: render result :rtype: [string, string[]] """ Renderer.render_resource(self, categories, links, attributes) res = [] cat_s, cat_h = self.render_categories(categories) res += cat_h if links is not None: res += self.render_links(links) if attributes is not None: res += self.render_attributes(attributes) return ['', res]
[docs] def parse_header_values(self, body): """Helper generator method to split values in HTTP Header. :param string body: parsed text :return: result values :rtype: string """ m = None while body: m = HTTPHeadersRenderer.reHeaderChunk.match(body) #print m #if m: # print m.groupdict() # print m.end() # error on empty match if m is None or m.group('chunk') is None or m.end() == 0: raise occi.ParseError('Bad quoting in HTTP Headers', body) m = None break chunk = m.group('chunk') body = body[m.end():] if body and not m.group('sep'): raise occi.ParseError('Separator expected in HTTP Headers (%s)' % chunk, body) m = None break yield chunk.strip(' \t') #print 'remains: #%s#' % body if m and m.group('sep'): yield ''
[docs] def parse_categories(self, body, headers): """Parse OCCI Category Collection Beware of HTTP Headers size limitations. It is better to not use 'text/occi' mimetype for transfering OCCI Category Collection. :param string body[]: text to parse (unused in plain/occi) :param string headers[]: headers to parse :return: Array of OCCI Categories :rtype: occi.Category[] """ categories = [] category_ids = set() for line in headers: line = line.rstrip('\r\n') matched = TextRenderer.reCategory.match(line) if not matched: continue line = line[matched.end():] #print 'CATEGORY HIT:' #print line bodies = self.parse_header_values(line) #print 'SPLAT BODIES:' #print '\n\n'.join(bodies) for cat_s in bodies: # use the helper parser function inherited from text/plain renderer category = TextRenderer.parse_category_body(self, cat_s) # check uniqueness key = category['term'] + category['scheme'] if key in category_ids: raise occi.ParseError('Category not unique (term "%s", scheme "%s")' % (category['term'], category['scheme']), cat_s) category_ids.add(key) categories.append(category) return categories
[docs] def parse_locations(self, body, headers): """Parse OCCI Entity collection :param string body[]: text to parse (unused in text/occi) :param string headers[]: headers to parse :return: Array of links :rtype: string[] """ locations = [] for line in headers: line = line.rstrip('\r\n') matched = TextRenderer.reLocation.match(line) if not matched: continue uris_str = matched.group(2) uris = self.parse_header_values(uris_str) for uri in uris: if not check_url(uri, scheme=True, host=True): raise occi.ParseError('Invalid URI in OCCI Entity collection', line) locations.append(uri) return locations
[docs] def parse_resource(self, body, headers): """Parse OCCI Resource instance :param string body[]: text to parse (unused in text/occi) :param string headers[]: headers to parse :return: categories, links, and attributes :rtype: [occi.Category categories[], occi.Link links[], occi.Attribute attributes[]] """ categories = [] links = [] attributes = [] for line in headers: line = line.rstrip('\r\n') matched = TextRenderer.reCategory.match(line) if matched is not None: cats_str = line[matched.end():] for s in self.parse_header_values(cats_str): categories.append(self.parse_category_body(s)) continue matched = TextRenderer.reLink.match(line) if matched is not None: links_str = line[matched.end():] for s in self.parse_header_values(links_str): links.append(self.parse_link_body(s)) continue matched = TextRenderer.reAttribute.match(line) if matched is not None: attrs_str = line[matched.end():] for s in self.parse_header_values(attrs_str): attributes.append(self.parse_attribute_body(s)) continue else: continue return [categories, links, attributes]