@@ -281,7 +281,7 @@ async def _handle(self, request: Request) -> Response:
281281 self ._document .language ,
282282 list (self ._document .localizations ),
283283 )
284- exchange = _Exchange (headers = headers , language = language , method = method )
284+ exchange = _Exchange (headers = headers , language = self . _document . language , method = method )
285285 if request .path == "/.well-known/odp" :
286286 _require_method (effective , ("GET" ,))
287287 return _json_response (self ._document , _MAXIMUM_DOCUMENT_BYTES , exchange )
@@ -295,7 +295,7 @@ async def _handle(self, request: Request) -> Response:
295295 item .name for item in self ._document .operations
296296 }:
297297 raise RequestError (404 , "NOT_FOUND" , "ODP operation is not supported" )
298- catalog_request = _catalog_request (request , headers , language )
298+ catalog_request = _catalog_request (request , headers , language , operation )
299299 if (effective , path ) == ("GET" , "/offerings" ):
300300 offering_page = await self ._catalog .list_offerings (catalog_request )
301301 return _json_response (
@@ -370,7 +370,9 @@ async def _get_path(self, path: str, request: CatalogRequest, exchange: _Exchang
370370 raise RequestError (404 , "NOT_FOUND" , "ODP resource not found" )
371371
372372
373- def _catalog_request (request : Request , headers : dict [str , str ], language : str ) -> CatalogRequest :
373+ def _catalog_request (
374+ request : Request , headers : dict [str , str ], language : str , operation : Operation | None
375+ ) -> CatalogRequest :
374376 parameters = parse_qsl (request .query , keep_blank_values = True )
375377 # SVC-73: a repeated `representation` is rejected rather than resolved. Collapsing repeats into
376378 # a dict silently honoured whichever copy came last, so `representation=terse&representation=
@@ -381,7 +383,10 @@ def _catalog_request(request: Request, headers: dict[str, str], language: str) -
381383 raise RequestError (400 , "INVALID_REQUEST" , f"{ name } must not be repeated" )
382384 values [name ] = value
383385 try :
384- representation = Representation (values .get ("representation" , "terse" ))
386+ default = (
387+ "full" if operation in {Operation .GET_COLLECTION , Operation .GET_OFFERING } else "terse"
388+ )
389+ representation = Representation (values .get ("representation" , default ))
385390 limit = int (values .get ("limit" , "0" ))
386391 except ValueError as error :
387392 raise RequestError (400 , "INVALID_REQUEST" , "query parameter is invalid" ) from error
@@ -434,9 +439,20 @@ def _json_response(value: object, maximum_bytes: int, exchange: _Exchange) -> Re
434439 body = _encode (value )
435440 if len (body ) > maximum_bytes :
436441 raise ServiceError ("response body is too large" )
437- etag = _entity_tag (exchange .language , body )
442+ if isinstance (value , Page ):
443+ language = (
444+ ", " .join (
445+ dict .fromkeys (
446+ getattr (item , "language" , "" ) or exchange .language for item in value .items
447+ )
448+ )
449+ or exchange .language
450+ )
451+ else :
452+ language = getattr (value , "language" , "" ) or exchange .language
453+ etag = _entity_tag (language , body )
438454 headers = {
439- "content-language" : exchange . language ,
455+ "content-language" : language ,
440456 "content-type" : MEDIA_TYPE ,
441457 "etag" : etag ,
442458 "vary" : "Accept, Accept-Language" ,
@@ -554,12 +570,20 @@ def _require_accept(value: str | None) -> None:
554570 """
555571 if value is None :
556572 return
573+ specificity = - 1
574+ quality = 0.0
557575 for entry in value .split ("," ):
558576 media_type = entry .split (";" , 1 )[0 ].strip ().lower ()
559577 if media_type not in {"*/*" , "application/*" , MEDIA_TYPE }:
560578 continue
561- if _quality_of (entry ) > 0 :
562- return
579+ precision = {"*/*" : 0 , "application/*" : 1 , MEDIA_TYPE : 2 }[media_type ]
580+ weight = _quality_of (entry )
581+ if precision > specificity :
582+ specificity , quality = precision , weight
583+ elif precision == specificity :
584+ quality = max (quality , weight )
585+ if quality > 0 :
586+ return
563587 raise RequestError (406 , "NOT_ACCEPTABLE" , f"Accept must allow { MEDIA_TYPE } " )
564588
565589
0 commit comments