88import pathlib
99import secrets
1010import urllib
11+ import urllib .parse
1112import urllib .request
1213from typing import Any , Dict , List , Optional , Tuple , Union
1314
2021logger = logging .getLogger ("zocalo.util.rabbitmq" )
2122
2223
24+ def _quote (arg : str ) -> str :
25+ """URL-quote a VHost name (which can contain /)"""
26+ return urllib .parse .quote (arg , safe = [])
27+
28+
2329class MessageStats (BaseModel ):
2430 publish : Optional [int ] = Field (None , description = "Count of messages published." )
2531
@@ -750,7 +756,7 @@ def bindings(
750756 ) -> List [BindingInfo ]:
751757 endpoint = "bindings"
752758 if vhost is not None :
753- endpoint = f"{ endpoint } /{ vhost } "
759+ endpoint = f"{ endpoint } /{ _quote ( vhost ) } "
754760 _check = {source , destination , destination_type }
755761 if None in _check and len (_check ) > 1 :
756762 raise ValueError (
@@ -789,7 +795,9 @@ def bindings_delete(
789795 ):
790796 # If properties_key is not specified then all bindings between the specified
791797 # source and destination are deleted
792- endpoint = f"bindings/{ vhost } /e/{ source } /{ destination_type } /{ destination } "
798+ endpoint = (
799+ f"bindings/{ _quote (vhost )} /e/{ source } /{ destination_type } /{ destination } "
800+ )
793801 if properties_key is None :
794802 dest_map = {"queue" : "q" , "exchange" : "e" }
795803
@@ -834,11 +842,11 @@ def exchanges(
834842 ) -> Union [List [ExchangeInfo ], ExchangeInfo ]:
835843 endpoint = "exchanges"
836844 if vhost is not None and name is not None :
837- endpoint = f"{ endpoint } /{ vhost } /{ name } /"
845+ endpoint = f"{ endpoint } /{ _quote ( vhost ) } /{ name } /"
838846 response = self .get (endpoint )
839847 return ExchangeInfo (** response .json ())
840848 elif vhost is not None :
841- endpoint = f"{ endpoint } /{ vhost } /"
849+ endpoint = f"{ endpoint } /{ _quote ( vhost ) } /"
842850 elif name is not None :
843851 raise ValueError ("name can not be set without vhost" )
844852 response = self .get (endpoint )
@@ -853,19 +861,19 @@ def exchange_declare(self, exchange: ExchangeSpec):
853861 response .raise_for_status ()
854862
855863 def exchange_delete (self , vhost : str , name : str , if_unused : bool = False ):
856- endpoint = f"exchanges/{ vhost } /{ name } "
864+ endpoint = f"exchanges/{ _quote ( vhost ) } /{ name } "
857865 response = self .delete (endpoint , params = {"if-unused" : if_unused })
858866 response .raise_for_status ()
859867
860868 def policies (self , vhost : Optional [str ] = None ) -> List [PolicySpec ]:
861869 endpoint = "policies"
862870 if vhost is not None :
863- endpoint = f"{ endpoint } /{ vhost } /"
871+ endpoint = f"{ endpoint } /{ _quote ( vhost ) } /"
864872 response = self .get (endpoint )
865873 return [PolicySpec (** p ) for p in response .json ()]
866874
867875 def policy (self , vhost : str , name : str ) -> PolicySpec :
868- endpoint = f"policies/{ vhost } /{ name } /"
876+ endpoint = f"policies/{ _quote ( vhost ) } /{ name } /"
869877 response = self .get (endpoint )
870878 return PolicySpec (** response .json ())
871879
@@ -880,7 +888,7 @@ def set_policy(self, policy: PolicySpec):
880888 response .raise_for_status ()
881889
882890 def clear_policy (self , vhost : str , name : str ):
883- endpoint = f"policies/{ vhost } /{ name } /"
891+ endpoint = f"policies/{ _quote ( vhost ) } /{ name } /"
884892 response = self .delete (endpoint )
885893 response .raise_for_status ()
886894
@@ -889,11 +897,11 @@ def queues(
889897 ) -> Union [List [QueueInfo ], QueueInfo ]:
890898 endpoint = "queues"
891899 if vhost is not None and name is not None :
892- endpoint = f"{ endpoint } /{ vhost } /{ name } "
900+ endpoint = f"{ endpoint } /{ _quote ( vhost ) } /{ name } "
893901 response = self .get (endpoint )
894902 return QueueInfo (** response .json ())
895903 elif vhost is not None :
896- endpoint = f"{ endpoint } /{ vhost } "
904+ endpoint = f"{ endpoint } /{ _quote ( vhost ) } "
897905 elif name is not None :
898906 raise ValueError ("name can not be set without vhost" )
899907 response = self .get (endpoint )
@@ -910,7 +918,8 @@ def queue_declare(self, queue: QueueSpec):
910918 def queue_delete (
911919 self , vhost : str , name : str , if_unused : bool = False , if_empty : bool = False
912920 ):
913- endpoint = f"queues/{ vhost } /{ name } "
921+ logger .debug (f"Deleting queue { _quote (vhost )} /{ name } " )
922+ endpoint = f"queues/{ _quote (vhost )} /{ name } "
914923 response = self .delete (
915924 endpoint , params = {"if-unused" : if_unused , "if-empty" : if_empty }
916925 )
@@ -931,7 +940,7 @@ def permissions(
931940 ) -> List [PermissionSpec ] | PermissionSpec :
932941 endpoint = "permissions"
933942 if vhost is not None and user is not None :
934- endpoint = f"{ endpoint } /{ vhost } /{ user } /"
943+ endpoint = f"{ endpoint } /{ _quote ( vhost ) } /{ user } /"
935944 response = self .get (endpoint )
936945 return PermissionSpec (** response .json ())
937946 elif vhost is not None or user is not None :
@@ -950,7 +959,7 @@ def set_permissions(self, permission: PermissionSpec):
950959 response .raise_for_status ()
951960
952961 def clear_permissions (self , vhost : str , user : str ):
953- endpoint = f"permissions/{ vhost } /{ user } /"
962+ endpoint = f"permissions/{ _quote ( vhost ) } /{ user } /"
954963 response = self .delete (endpoint )
955964 response .raise_for_status ()
956965
0 commit comments