def __init__(self, service): Resource.__init__(self) self.service = service self.resources = { '/capoeira/events/similar/artist': self.service.capoeiraSimilarByArtistQuery, '/capoeira/events/similar/track': self.service.capoeiraSimilarByTrackQuery } self.isLeaf = True # default_params is used in lieu of a defined Accept field in the header default_params = AcceptParameters(ContentType("text/html"), Language("en")) acceptable = [ AcceptParameters(ContentType("text/html"), Language("en")), AcceptParameters(ContentType("text/json"), Language("en")), AcceptParameters(ContentType("application/json"), Language("en")) ] self.contentNegotiator = ContentNegotiator(default_params, acceptable) # function mapping for rendering response self.renderFns = { 'text/html': formatHTMLResponse, 'text/json': formatJSONResponse, 'application/json': formatJSONResponse }
def test_unsupported_by_server(self): """ en only, unsupported by server """ accept_language = "en" server = [AcceptParameters(language=Language("de"))] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept_language=accept_language) assert accept_parameters is None
def test_text_plain_only(self): """ text/plain only """ client_accept = "text/plain" server = [AcceptParameters(ContentType("text/plain"))] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept=client_accept) assert str(accept_parameters.content_type) == "text/plain"
def test_en_only(self): """ en only """ accept_language = "en" server = [AcceptParameters(language=Language("en"))] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept_language=accept_language) assert str(accept_parameters.language) == "en"
def test_unsupported_by_server(self): """ text/plain only, unsupported by server """ client_accept = "text/plain" server = [AcceptParameters(ContentType("text/html"))] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept=client_accept) assert accept_parameters is None
def test_partially_supported_by_server(self): """ en, partially supported by server """ accept_language = "en" server = [AcceptParameters(language=Language("en-gb"))] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept_language=accept_language) assert str(accept_parameters.language) == "en-gb"
def _GET_container(self, path=None): """ GET a representation of the container in the appropriate (content negotiated) format as identified by the supplied id Args: - id: The ID of the container as supplied in the request URL Returns a representation of the container: SSS will return either the Atom Entry identical to the one supplied as a deposit receipt or the pure RDF/XML Statement depending on the Accept header """ ssslog.debug( "GET on Container (retrieve deposit receipt or statement); Incoming HTTP headers: " + str(request.environ)) # authenticate try: auth = self.authenticate() ss = SwordServer(config, auth) # first thing we need to do is check that there is an object to return, because otherwise we may throw a # 415 Unsupported Media Type without looking first to see if there is even any media to content negotiate for # which would be weird from a client perspective if not ss.container_exists(path): return self.manage_error(SwordError(status=404, empty=True)) # get the content negotiation headers accept_header = request.environ.get("HTTP_ACCEPT") accept_packaging_header = request.environ.get( "HTTP_ACCEPT_PACKAGING") # do the negotiation default_accept_parameters, acceptable = config.get_container_formats( ) cn = ContentNegotiator(default_accept_parameters, acceptable) accept_parameters = cn.negotiate(accept=accept_header) ssslog.info("Container requested in format: " + str(accept_parameters)) # did we successfully negotiate a content type? if accept_parameters is None: raise SwordError(error_uri=Error.content, status=415, empty=True) # now actually get hold of the representation of the container and send it to the client cont = ss.get_container(path, accept_parameters) ssslog.info("Returning " + response.status + " from request on " + inspect.stack()[0][3]) if cont is not None: response.headers["Content-Type"] = str( accept_parameters.content_type.mimetype()) return cont except SwordError as e: return self.manage_error(e)
def _GET_media_resource(self, path=None): """ GET the media resource content in the requested format (web request will include content negotiation via Accept header) Args: - id: the ID of the object in the store Returns the content in the requested format """ ssslog.debug("GET on MediaResource; Incoming HTTP headers: " + str(request.environ)) # NOTE: this method is not authenticated - we imagine sharing this URL with end-users who will just want # to retrieve the content. ss = SwordServer(config, None) # first thing we need to do is check that there is an object to return, because otherwise we may throw a # 406 Not Acceptable without looking first to see if there is even any media to content negotiate for # which would be weird from a client perspective if not ss.media_resource_exists(path): return self.manage_error(SwordError(status=404, empty=True)) # get the content negotiation headers accept_header = request.environ.get("HTTP_ACCEPT") accept_packaging_header = request.environ.get("HTTP_ACCEPT_PACKAGING") # do the negotiation default_accept_parameters, acceptable = config.get_media_resource_formats( ) cn = ContentNegotiator(default_accept_parameters, acceptable) accept_parameters = cn.negotiate( accept=accept_header, accept_packaging=accept_packaging_header) ssslog.info("Conneg format: " + str(accept_parameters)) try: # can get hold of the media resource media_resource = ss.get_media_resource(path, accept_parameters) except SwordError as e: return self.manage_error(e) # either send the client a redirect, or stream the content out if media_resource.redirect: redirect(media_resource.url, _code=302) # FOUND (not SEE OTHER) return else: response.content_type = media_resource.content_type if media_resource.packaging is not None: response.headers["Packaging"] = str(media_resource.packaging) f = open(media_resource.filepath, "r") response.status_int = 200 response.status = "200 OK" ssslog.info("Returning " + response.status + " from request on " + inspect.stack()[0][3]) return f.read()
def test_unsupported_by_server(self): """ en-gb, unsupported by server """ accept_language = "en-gb" server = [AcceptParameters(language=Language("en"))] cn = ContentNegotiator( acceptable=server, ignore_language_variants=False ) accept_parameters = cn.negotiate(accept_language=accept_language) assert accept_parameters is None
def test_supported_by_server_through_language_variants(self): """ en-gb, supported by server through language variants """ accept_language = "en-gb" server = [AcceptParameters(language=Language("en"))] cn = ContentNegotiator( acceptable=server, ignore_language_variants=True ) accept_parameters = cn.negotiate(accept_language=accept_language) assert str(accept_parameters.language) == "en"
def test_mixed_q_values_most_preferred_available(self): """ en vs no vs de with mixed q values, most preferred available """ accept_language = "en;q=0.6, no;q=0.9, de" server = [ AcceptParameters(language=Language("no")), AcceptParameters(language=Language("de")), ] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept_language=accept_language) assert str(accept_parameters.language) == "de"
def test_image_wildcard_supported_by_serverwith_other_options_primary_option_supported(self): """ * with other options, primary option supported """ accept_language = "en, *" server = [ AcceptParameters(language=Language("en")), AcceptParameters(language=Language("de")), ] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept_language=accept_language) assert str(accept_parameters.language) == "en"
def test_with_q_values(self): """ application/atom+xml vs application/rdf+xml with q values """ client_accept = "application/atom+xml;q=0.6, application/rdf+xml;q=0.9" server = [ AcceptParameters(ContentType("application/rdf+xml")), AcceptParameters(ContentType("application/atom+xml")), ] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept=client_accept) assert str(accept_parameters.content_type) == "application/rdf+xml"
def test_wildcard_by_itself(self): """ * by itself """ accept_language = "*" server = [ AcceptParameters(language=Language("no")), AcceptParameters(language=Language("de")), ] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept_language=accept_language) assert str(accept_parameters.language) == "no"
def test_with_q_values(self): """ fr vs no with q values """ accept_language = "fr;q=0.7, no;q=0.8" server = [ AcceptParameters(language=Language("fr")), AcceptParameters(language=Language("no")), ] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept_language=accept_language) assert str(accept_parameters.language) == "no"
def test_without_q_values(self): """ en vs de without q values """ accept_language = "en, de" server = [ AcceptParameters(language=Language("en")), AcceptParameters(language=Language("de")), ] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept_language=accept_language) assert str(accept_parameters.language) == "en"
def test_content_type_and_language_specified(self): """ content type and language specified """ accept = "text/html" accept_lang = "en" server = [AcceptParameters(ContentType("text/html"), Language("en"))] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate( accept=accept, accept_language=accept_lang ) assert str(accept_parameters.content_type) == "text/html" assert str(accept_parameters.language) == "en"
def test_any_supported_by_server(self): """ */* supported by server """ client_accept = "*/*" server = [ AcceptParameters(ContentType("text/plain")), AcceptParameters(ContentType("image/png")), AcceptParameters(ContentType("image/jpeg")), ] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept=client_accept) assert str(accept_parameters.content_type) == "text/plain"
def test_with_mixed_q_values(self): """ en vs de vs fr with mixed q values """ accept_language = "en;q=0.6, de;q=0.9, fr" server = [ AcceptParameters(language=Language("en")), AcceptParameters(language=Language("de")), AcceptParameters(language=Language("fr")), ] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept_language=accept_language) assert str(accept_parameters.language) == "fr"
def test_atom_with_type_feed_supported_by_server(self): """ application/atom+xml;type=feed supported by server """ client_accept = "application/atom+xml;type=feed" server = [ AcceptParameters(ContentType("application/atom+xml;type=feed")) ] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept=client_accept) assert ( str(accept_parameters.content_type) == "application/atom+xml;type=feed" )
def determine_content_type(self, request): acceptable = ( AcceptParameters(ContentType('application/json')), AcceptParameters(ContentType('application/hal+json')), AcceptParameters(ContentType('application/vnd.siren+json')), ) negotiator = ContentNegotiator(acceptable[0], acceptable) accept = request.META.get('HTTP_ACCEPT') negotiated_type = negotiator.negotiate(accept=request.META.get('HTTP_ACCEPT')) if negotiated_type: return negotiated_type.content_type return acceptable[0].content_type
def test_mixed_q_values_most_preferred_available(self): """ application/atom+xml vs application/rdf+xml vs text/html with mixed q values, most preferred available """ client_accept = ( "application/atom+xml;q=0.6, application/rdf+xml;q=0.9, text/html" ) server = [ AcceptParameters(ContentType("application/rdf+xml")), AcceptParameters(ContentType("text/html")), ] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate(accept=client_accept) assert str(accept_parameters.content_type) == "text/html"
def GET(self, path): """ GET the media resource content in the requested format (web request will include content negotiation via Accept header) Args: - id: the ID of the object in the store Returns the content in the requested format """ ssslog.debug("GET on MediaResourceContent; Incoming HTTP headers: " + str(web.ctx.environ)) # NOTE: this method is not authenticated - we imagine sharing this URL with end-users who will just want # to retrieve the content. It's only for the purposes of example, anyway ss = SwordServer(config, None) # first thing we need to do is check that there is an object to return, because otherwise we may throw a # 406 Not Acceptable without looking first to see if there is even any media to content negotiate for # which would be weird from a client perspective if not ss.media_resource_exists(path): return web.notfound() # get the content negotiation headers accept_header = web.ctx.environ.get("HTTP_ACCEPT") accept_packaging_header = web.ctx.environ.get("HTTP_ACCEPT_PACKAGING") # do the negotiation default_accept_parameters, acceptable = config.get_media_resource_formats() cn = ContentNegotiator(default_accept_parameters, acceptable) accept_parameters = cn.negotiate(accept=accept_header, accept_packaging=accept_packaging_header) ssslog.info("Conneg format: " + str(accept_parameters)) try: # can get hold of the media resource media_resource = ss.get_media_resource(path, accept_parameters) except SwordError as e: ssslog.debug("Raised error") return self.manage_error(e) # either send the client a redirect, or stream the content out if media_resource.redirect: return web.found(media_resource.url) else: web.header("Content-Type", media_resource.content_type) if media_resource.packaging is not None: web.header("Packaging", media_resource.packaging) f = open(media_resource.filepath, "r") web.ctx.status = "200 OK" return f.read()
def test_two_content_types_and_two_languages_specified(self): """ Two content types and 2 languages specified """ accept = "text/html, text/plain" accept_lang = "en, de" server = [ AcceptParameters(ContentType("text/html"), Language("de")), AcceptParameters(ContentType("text/plain"), Language("en")), ] cn = ContentNegotiator(acceptable=server) accept_parameters = cn.negotiate( accept=accept, accept_language=accept_lang ) assert str(accept_parameters.content_type) == "text/html" assert str(accept_parameters.language) == "de"
def get(self, request): content_type_to_acceptable = lambda content_type: AcceptParameters( ContentType(content_type)) acceptable = map(content_type_to_acceptable, self.content_type_providers().keys()) preferred_content_type = self.preferred_content_type accept = request.headers.get('ACCEPT') negotiator = ContentNegotiator( content_type_to_acceptable(preferred_content_type), acceptable) negotiated_type = negotiator.negotiate(accept=accept) content_type = negotiated_type.content_type or preferred_content_type provider = self.content_type_providers()[str(content_type)] return provider()
def getFormat(self, request): defaultOutput = AcceptParameters( ContentType(self.defaultOutputFormat, params='q=0')) acceptable = [defaultOutput] + [ AcceptParameters(ContentType(x)) for x in self._outputFormatsPreference ] cn = ContentNegotiator(defaultOutput, acceptable) if request.requestHeaders.hasHeader("Accept"): kwargs = { "accept": request.requestHeaders.getRawHeaders("Accept")[0] } else: kwargs = {} accp = cn.negotiate(**kwargs) return str(accp.content_type) if accp else None
def test_two_content_types_and_one_language_specified_with_weights(self): """ Two content types and one language specified, with weights """ weights = { "content_type": 2.0, "language": 1.0, "charset": 1.0, "encoding": 1.0, } accept = "text/html, text/plain" accept_lang = "en" server = [ AcceptParameters(ContentType("text/html"), Language("de")), AcceptParameters(ContentType("text/plain"), Language("en")), ] cn = ContentNegotiator(acceptable=server, weights=weights) accept_parameters = cn.negotiate( accept=accept, accept_language=accept_lang ) assert str(accept_parameters.content_type) == "text/plain" assert str(accept_parameters.language) == "en"
def _init_content_negotiator(self): #TODO: use config instead default_content_type = "application/ld+json" default_accept_params = AcceptParameters( ContentType(default_content_type)) # rdf types rdf_types = set([ plugin.name for plugin in plugins(kind=Serializer) if "/" in plugin.name ]) #Blacklisted because mapped to TriX that requires a context-aware store blacklisted_types = ["application/xml"] #TODO: consider other types accepted_types = list( rdf_types.difference(blacklisted_types)) + ["application/json"] self._logger.debug("Accepted types: %s" % accepted_types) acceptable_params = [default_accept_params] + [ AcceptParameters(ContentType(ct)) for ct in accepted_types ] self._negotiator = ContentNegotiator(default_accept_params, acceptable_params)