Coverage for aiocoap/numbers/optionnumbers.py: 94%
101 statements
« prev ^ index » next coverage.py v7.6.8, created at 2024-11-28 12:34 +0000
« prev ^ index » next coverage.py v7.6.8, created at 2024-11-28 12:34 +0000
1# SPDX-FileCopyrightText: Christian Amsüss and the aiocoap contributors
2#
3# SPDX-License-Identifier: MIT
5"""Known values for CoAP option numbers
7The values defined in `OptionNumber` correspond to the IANA registry "CoRE
8Parameters", subregistries "CoAP Method Codes" and "CoAP Response Codes".
10The option numbers come with methods that can be used to evaluate their
11properties, see the `OptionNumber` class for details.
12"""
14import warnings
16from ..util import ExtensibleIntEnum
17from .. import optiontypes
20class OptionNumber(ExtensibleIntEnum):
21 """A CoAP option number.
23 As the option number contains information on whether the option is
24 critical, and whether it is safe-to-forward, those properties can be
25 queried using the `is_*` group of methods.
27 Note that whether an option may be repeated or not does not only depend on
28 the option, but also on the context, and is thus handled in the `Options`
29 object instead."""
31 IF_MATCH = 1
32 URI_HOST = 3
33 ETAG = 4
34 IF_NONE_MATCH = 5
35 OBSERVE = 6
36 URI_PORT = 7
37 LOCATION_PATH = 8
38 OSCORE = 9
39 URI_PATH = 11
40 CONTENT_FORMAT = 12
41 MAX_AGE = 14
42 URI_QUERY = 15
43 HOP_LIMIT = 16
44 ACCEPT = 17
45 Q_BLOCK1 = 19
46 LOCATION_QUERY = 20
47 EDHOC = 21
48 BLOCK2 = 23
49 BLOCK1 = 27
50 SIZE2 = 28
51 Q_BLOCK2 = 31
52 PROXY_URI = 35
53 PROXY_SCHEME = 39
54 SIZE1 = 60
55 ECHO = 252
56 NO_RESPONSE = 258
57 REQUEST_TAG = 292
59 # experimental for draft-amsuess-core-cachable-oscore
60 #
61 # Using the number suggested there (rather than a high one) as this is
62 # going to be used in overhead comparisons.
63 REQUEST_HASH = 548
65 @property
66 def OBJECT_SECURITY(self):
67 warnings.warn("OBJECT_SECURITY is a deprecated alias for OSCORE")
68 return self.OSCORE
70 def __add__(self, delta):
71 """Addition makes sense on these due to the delta encoding in CoAP
72 serialization"""
73 return type(self)(int(self) + delta)
75 def is_critical(self):
76 return self & 0x01 == 0x01
78 def is_elective(self):
79 return not self.is_critical()
81 def is_unsafe(self):
82 return self & 0x02 == 0x02
84 def is_safetoforward(self):
85 return not self.is_unsafe()
87 def is_nocachekey(self):
88 if self.is_unsafe():
89 raise ValueError("NoCacheKey is only meaningful for safe options")
90 return self & 0x1E == 0x1C
92 def is_cachekey(self):
93 return not self.is_nocachekey()
95 def _get_format(self):
96 if hasattr(self, "_format"):
97 return self._format
98 else:
99 return optiontypes.OpaqueOption
101 def set_format(self, value):
102 """Set the serialization format.
104 This affects any use of the option throughout the program; existing
105 options should not be altered incompatibly. Use this on custom or
106 experimental options.
108 This is available as a setter function in addition to write access
109 through the `format` property to satisfy requirements imposed by mypy's
110 special handling of enums.
111 """
112 if hasattr(self, "_format"):
113 if self._format != value:
114 warnings.warn(
115 "Altering the serialization format of {self}. This is a severe interoperability hazard with other modules, and should only be used during experimentation. This warning may be converted into an error at any time."
116 )
117 self._format = value
119 format = property(
120 _get_format,
121 set_format,
122 doc="Serialization format; see :func:`~aiocoap.numbers.optionnumbers.OptionNumber.set_format`",
123 )
125 def create_option(self, decode=None, value=None):
126 """Return an Option element of the appropriate class from this option
127 number.
129 An initial value may be set using the decode or value options, and will
130 be fed to the resulting object's decode method or value property,
131 respectively."""
132 option = self.format(self)
133 if decode is not None:
134 option.decode(decode)
135 if value is not None:
136 option.value = value
137 return option
139 def _repr_html_(self):
140 import html
142 properties = f"{'critical' if self.is_critical() else 'elective'}, {'safe-to-forward' if self.is_safetoforward() else 'proxy unsafe'}"
143 if self.is_safetoforward():
144 properties += (
145 ", part of the cache key"
146 if self.is_cachekey()
147 else ", not part of the cache key"
148 )
149 if hasattr(self, "name"):
150 return f'<abbr title="option {int(self)}: {properties}">{html.escape(self.name)}</abbr>'
151 else:
152 return f'<abbr title="{properties}">Option {int(self)}</abbr>'
155# OpaqueOption is set on formats where it is known to be used even though it is
156# the default. This allows developers to rely on those interfaces to be stable
157# (or at least to be notified visibly in the release notes).
159# RFC 7252
161OptionNumber.IF_MATCH.set_format(optiontypes.OpaqueOption)
162OptionNumber.URI_HOST.set_format(optiontypes.StringOption)
163OptionNumber.ETAG.set_format(optiontypes.OpaqueOption)
164OptionNumber.URI_PORT.set_format(optiontypes.UintOption)
165OptionNumber.LOCATION_PATH.set_format(optiontypes.StringOption)
166OptionNumber.URI_PATH.set_format(optiontypes.StringOption)
167OptionNumber.CONTENT_FORMAT.set_format(optiontypes.ContentFormatOption)
168OptionNumber.MAX_AGE.set_format(optiontypes.UintOption)
169OptionNumber.URI_QUERY.set_format(optiontypes.StringOption)
170OptionNumber.ACCEPT.set_format(optiontypes.ContentFormatOption)
171OptionNumber.LOCATION_QUERY.set_format(optiontypes.StringOption)
172OptionNumber.PROXY_URI.set_format(optiontypes.StringOption)
173OptionNumber.PROXY_SCHEME.set_format(optiontypes.StringOption)
174OptionNumber.SIZE1.set_format(optiontypes.UintOption)
176# RFC 7959
178OptionNumber.BLOCK2.set_format(optiontypes.BlockOption)
179OptionNumber.BLOCK1.set_format(optiontypes.BlockOption)
180OptionNumber.SIZE2.set_format(optiontypes.UintOption)
182# RFC 7641
184OptionNumber.OBSERVE.set_format(optiontypes.UintOption)
186# RFC 7967
188OptionNumber.NO_RESPONSE.set_format(optiontypes.UintOption)
190# RFC 8613
192OptionNumber.OSCORE.set_format(optiontypes.OpaqueOption)
194# RFC 9175
196OptionNumber.ECHO.set_format(optiontypes.OpaqueOption)
197OptionNumber.REQUEST_TAG.set_format(optiontypes.OpaqueOption)
199# RFC 8768
201OptionNumber.HOP_LIMIT.set_format(optiontypes.UintOption)
203# experimental for draft-amsuess-core-cachable-oscore
205OptionNumber.REQUEST_HASH.set_format(optiontypes.OpaqueOption)