Skip to content

Commit 9950e0d

Browse files
committed
revised switch field arglist (removed length)
1 parent fc657f1 commit 9950e0d

File tree

11 files changed

+115
-100
lines changed

11 files changed

+115
-100
lines changed

pcapkit/corekit/fields/field.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,6 @@ def template(self) -> 'str':
194194
"""Field template."""
195195
return self._template
196196

197-
@property
198-
def length(self) -> 'int':
199-
"""Field size."""
200-
return struct.calcsize(self.template)
201-
202197
def __init__(self, length: 'int | Callable[[dict[str, Any]], int]',
203198
default: '_T | NoValueType' = NoValue,
204199
callback: 'Callable[[Self, dict[str, Any]], None]' = lambda *_: None) -> 'None':

pcapkit/corekit/fields/misc.py

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def __call__(self, packet: 'dict[str, Any]') -> 'Self':
146146
"""
147147
new_self = copy.copy(self)
148148
if new_self._condition(packet):
149-
new_self._field(packet)
149+
new_self._field = new_self._field(packet)
150150
return new_self
151151

152152
def pre_process(self, value: '_TC', packet: 'dict[str, Any]') -> 'Any': # pylint: disable=unused-argument
@@ -356,20 +356,57 @@ class SwitchField(_Field[_TC]):
356356
"""Conditional type-switching field for protocol schema.
357357
358358
Args:
359-
length: Field size (in bytes); if a callable is given, it should return
360-
an integer value and accept the current packet as its only argument.
361359
selector: Callable function to select field type, which should accept
362360
the current packet as its only argument and return a field instance.
363361
364362
"""
365363

364+
@property
365+
def name(self) -> 'str':
366+
"""Field name."""
367+
return self._field.name
368+
369+
@name.setter
370+
def name(self, value: 'str') -> 'None':
371+
"""Set field name."""
372+
self._field.name = value
373+
374+
@property
375+
def default(self) -> '_TC | NoValueType':
376+
"""Field default value."""
377+
return self._field.default
378+
379+
@default.setter
380+
def default(self, value: '_TC | NoValueType') -> 'None':
381+
"""Set field default value."""
382+
self._field.default = value
383+
384+
@default.deleter
385+
def default(self) -> 'None':
386+
"""Delete field default value."""
387+
self._field.default = NoValue
388+
389+
@property
390+
def template(self) -> 'str':
391+
"""Field template."""
392+
return self._field.template
393+
394+
@property
395+
def length(self) -> 'int':
396+
"""Field size."""
397+
return self._field.length
398+
366399
@property
367400
def optional(self) -> 'bool':
368401
"""Field is optional."""
369402
return True
370403

371-
def __init__(self, length: 'int | Callable[[dict[str, Any]], int]' = lambda _: -1,
372-
selector: 'Callable[[dict[str, Any]], _Field[_TC]]' = lambda _: NoValueField()) -> 'None': # type: ignore[assignment,return-value]
404+
@property
405+
def field(self) -> '_Field[_TC]':
406+
"""Field instance."""
407+
return self._field
408+
409+
def __init__(self, selector: 'Callable[[dict[str, Any]], _Field[_TC]]' = lambda _: NoValueField()) -> 'None': # type: ignore[assignment,return-value]
373410
self._name = '<switch>'
374411
self._field = cast('_Field[_TC]', NoValueField())
375412
self._selector = selector
@@ -390,7 +427,6 @@ def __call__(self, packet: 'dict[str, Any]') -> 'SwitchField[_TC]':
390427
"""
391428
new_self = copy.copy(self)
392429
new_self._field = self._selector(packet)(packet)
393-
new_self._template = new_self._field.template
394430
return new_self
395431

396432
def pre_process(self, value: '_TC', packet: 'dict[str, Any]') -> 'Any': # pylint: disable=unused-argument
@@ -522,7 +558,7 @@ def __call__(self, packet: 'dict[str, Any]') -> 'Self':
522558
new_self._callback(new_self, packet)
523559
if new_self._length_callback is not None:
524560
new_self._length = new_self._length_callback(packet)
525-
new_self._template = f'{new_self._length}s'
561+
new_self._template = f'{new_self._length}s' if self._length >= 0 else '1024s' # use a reasonable default
526562
return new_self
527563

528564
def pack(self, value: 'Optional[_TS | bytes]', packet: 'dict[str, Any]') -> 'bytes':
@@ -638,6 +674,24 @@ def __init__(self, field: '_Field[_TC]') -> 'None':
638674
self._name = '<forward_match>'
639675
self._field = field
640676

677+
def __call__(self, packet: 'dict[str, Any]') -> 'Self':
678+
"""Update field attributes.
679+
680+
Arguments:
681+
packet: Packet data.
682+
683+
Returns:
684+
Updated field instance.
685+
686+
Notes:
687+
This method will return a new instance of :class:`ConditionalField`
688+
instead of updating the current instance.
689+
690+
"""
691+
new_self = copy.copy(self)
692+
new_self._field = new_self._field(packet)
693+
return new_self
694+
641695
def pack(self, value: 'Optional[_TC]', packet: 'dict[str, Any]') -> 'bytes':
642696
"""Pack field value into :obj:`bytes`.
643697

pcapkit/protocols/schema/application/httpv2.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,26 +79,26 @@ def http_frame_selector(pkt: 'dict[str, Any]') -> 'Field':
7979
"""
8080
type = cast('Enum_Frame', pkt['type'])
8181
if type == Enum_Frame.DATA:
82-
return SchemaField(schema=DataFrame)
82+
return SchemaField(length=pkt['__length__'], schema=DataFrame)
8383
if type == Enum_Frame.HEADERS:
84-
return SchemaField(schema=HeadersFrame)
84+
return SchemaField(length=pkt['__length__'], schema=HeadersFrame)
8585
if type == Enum_Frame.PRIORITY:
86-
return SchemaField(schema=PriorityFrame)
86+
return SchemaField(length=pkt['__length__'], schema=PriorityFrame)
8787
if type == Enum_Frame.RST_STREAM:
88-
return SchemaField(schema=RSTStreamFrame)
88+
return SchemaField(length=pkt['__length__'], schema=RSTStreamFrame)
8989
if type == Enum_Frame.SETTINGS:
90-
return SchemaField(schema=SettingsFrame)
90+
return SchemaField(length=pkt['__length__'], schema=SettingsFrame)
9191
if type == Enum_Frame.PUSH_PROMISE:
92-
return SchemaField(schema=PushPromiseFrame)
92+
return SchemaField(length=pkt['__length__'], schema=PushPromiseFrame)
9393
if type == Enum_Frame.PING:
94-
return SchemaField(schema=PingFrame)
94+
return SchemaField(length=pkt['__length__'], schema=PingFrame)
9595
if type == Enum_Frame.GOAWAY:
96-
return SchemaField(schema=GoawayFrame)
96+
return SchemaField(length=pkt['__length__'], schema=GoawayFrame)
9797
if type == Enum_Frame.WINDOW_UPDATE:
98-
return SchemaField(schema=WindowUpdateFrame)
98+
return SchemaField(length=pkt['__length__'], schema=WindowUpdateFrame)
9999
if type == Enum_Frame.CONTINUATION:
100-
return SchemaField(schema=ContinuationFrame)
101-
return SchemaField(schema=UnassignedFrame)
100+
return SchemaField(length=pkt['__length__'], schema=ContinuationFrame)
101+
return SchemaField(length=pkt['__length__'], schema=UnassignedFrame)
102102

103103

104104
class HTTP(Schema):
@@ -125,7 +125,6 @@ class HTTP(Schema):
125125
})
126126
#: Frame payload.
127127
frame: 'FrameType' = SwitchField(
128-
length=lambda pkt: pkt['__length__'],
129128
selector=http_frame_selector,
130129
)
131130

pcapkit/protocols/schema/internet/hip.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,11 @@ def host_id_hi_selector(pkt: 'dict[str, Any]') -> 'Field':
158158
159159
"""
160160
if pkt['algorithm'] == Enum_HIAlgorithm.ECDSA:
161-
return SchemaField(schema=ECDSACurveHostIdentity)
161+
return SchemaField(length=pkt['hi_len'], schema=ECDSACurveHostIdentity)
162162
if pkt['algorithm'] == Enum_HIAlgorithm.ECDSA_LOW:
163-
return SchemaField(schema=ECDSALowCurveHostIdentity)
163+
return SchemaField(length=pkt['hi_len'], schema=ECDSALowCurveHostIdentity)
164164
if pkt['algorithm'] == Enum_HIAlgorithm.EdDSA:
165-
return SchemaField(schema=EdDSACurveHostIdentity)
165+
return SchemaField(length=pkt['hi_len'], schema=EdDSACurveHostIdentity)
166166
return BytesField(length=pkt['hi_len'])
167167

168168

@@ -239,7 +239,6 @@ class Locator(Schema):
239239
lifetime: 'int' = UInt32Field()
240240
#: Locator value.
241241
value: 'IPv6Address | LocatorData' = SwitchField(
242-
length=lambda pkt: pkt['len'] * 4,
243242
selector=locator_value_selector,
244243
)
245244

@@ -528,9 +527,7 @@ class HostIDParameter(Parameter):
528527
#: Algorithm type.
529528
algorithm: 'Enum_HIAlgorithm' = EnumField(length=2, namespace=Enum_HIAlgorithm)
530529
#: Host ID.
531-
hi: 'bytes | HostIdentity' = SwitchField(
532-
length=lambda pkt: pkt['hi_len'],
533-
selector=host_id_hi_selector)
530+
hi: 'bytes | HostIdentity' = SwitchField(selector=host_id_hi_selector)
534531
#: Domain ID.
535532
di: 'bytes' = BytesField(length=lambda pkt: pkt['di_data']['len'])
536533
#: Padding.

pcapkit/protocols/schema/internet/hopopt.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ def smf_dpd_data_selector(pkt: 'dict[str, Any]') -> 'Field':
158158
"""
159159
mode = Enum_SMFDPDMode.get(pkt['test']['mode'])
160160
if mode == Enum_SMFDPDMode.I_DPD:
161-
return SchemaField(schema=SMFIdentificationBasedDPDOption)
161+
return SchemaField(length=pkt['test']['len'], schema=SMFIdentificationBasedDPDOption)
162162
if mode == Enum_SMFDPDMode.H_DPD:
163-
return SchemaField(schema=SMFHashBasedDPDOption)
163+
return SchemaField(length=pkt['test']['len'], schema=SMFHashBasedDPDOption)
164164
raise FieldValueError(f'HOPOPT: invalid SMF DPD mode: {mode}')
165165

166166

@@ -220,9 +220,9 @@ def quick_start_data_selector(pkt: 'dict[str, Any]') -> 'Field':
220220
pkt['flags']['func'] = func
221221

222222
if func == Enum_QSFunction.Quick_Start_Request:
223-
return SchemaField(schema=QuickStartRequestOption)
223+
return SchemaField(length=5, schema=QuickStartRequestOption)
224224
if func == Enum_QSFunction.Report_of_Approved_Rate:
225-
return SchemaField(schema=QuickStartReportOption)
225+
return SchemaField(length=5, schema=QuickStartReportOption)
226226
raise FieldValueError(f'HOPOPT: invalid QS function: {func}')
227227

228228

@@ -327,7 +327,6 @@ class _SMFDPDOption(Schema):
327327
}))
328328
#: SMF DPD data.
329329
data: 'SMFIdentificationBasedDPDOption | SMFHashBasedDPDOption' = SwitchField(
330-
length=lambda pkt: pkt['test']['len'],
331330
selector=smf_dpd_data_selector,
332331
)
333332

@@ -364,8 +363,7 @@ class SMFIdentificationBasedDPDOption(SMFDPDOption):
364363
})
365364
#: TaggerID.
366365
tid: 'bytes | IPv4Address | IPv6Address' = ConditionalField(
367-
SwitchField(length=lambda pkt: pkt['info']['len'] + 1,
368-
selector=smf_i_dpd_tid_selector),
366+
SwitchField(selector=smf_i_dpd_tid_selector),
369367
lambda pkt: pkt['info']['type'] != 0,
370368
)
371369
#: Identifier.
@@ -446,7 +444,6 @@ class _QuickStartOption(Schema):
446444
}))
447445
#: QS data.
448446
data: 'QuickStartRequestOption | QuickStartReportOption' = SwitchField(
449-
length=5,
450447
selector=quick_start_data_selector,
451448
)
452449

pcapkit/protocols/schema/internet/ipv4.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ def quick_start_data_selector(pkt: 'dict[str, Any]') -> 'Field':
123123
pkt['flags']['func'] = func
124124

125125
if func == Enum_QSFunction.Quick_Start_Request:
126-
return SchemaField(schema=QuickStartRequestOption)
126+
return SchemaField(length=5, schema=QuickStartRequestOption)
127127
if func == Enum_QSFunction.Report_of_Approved_Rate:
128-
return SchemaField(schema=QuickStartReportOption)
128+
return SchemaField(length=5, schema=QuickStartReportOption)
129129
raise FieldValueError(f'HOPOPT: invalid QS function: {func}')
130130

131131

@@ -436,7 +436,6 @@ class _QSOption(Schema):
436436
}))
437437
#: QS data.
438438
data: 'QuickStartRequestOption | QuickStartReportOption' = SwitchField(
439-
length=5,
440439
selector=quick_start_data_selector,
441440
)
442441

pcapkit/protocols/schema/internet/ipv6_opts.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ def smf_dpd_data_selector(pkt: 'dict[str, Any]') -> 'Field':
158158
"""
159159
mode = Enum_SMFDPDMode.get(pkt['test']['mode'])
160160
if mode == Enum_SMFDPDMode.I_DPD:
161-
return SchemaField(schema=SMFIdentificationBasedDPDOption)
161+
return SchemaField(length=pkt['test']['len'], schema=SMFIdentificationBasedDPDOption)
162162
if mode == Enum_SMFDPDMode.H_DPD:
163-
return SchemaField(schema=SMFHashBasedDPDOption)
163+
return SchemaField(length=pkt['test']['len'], schema=SMFHashBasedDPDOption)
164164
raise FieldValueError(f'IPv6-Opts: invalid SMF DPD mode: {mode}')
165165

166166

@@ -220,9 +220,9 @@ def quick_start_data_selector(pkt: 'dict[str, Any]') -> 'Field':
220220
pkt['flags']['func'] = func
221221

222222
if func == Enum_QSFunction.Quick_Start_Request:
223-
return SchemaField(schema=QuickStartRequestOption)
223+
return SchemaField(length=5, schema=QuickStartRequestOption)
224224
if func == Enum_QSFunction.Report_of_Approved_Rate:
225-
return SchemaField(schema=QuickStartReportOption)
225+
return SchemaField(length=5, schema=QuickStartReportOption)
226226
raise FieldValueError(f'IPv6-Opts: invalid QS function: {func}')
227227

228228

@@ -327,7 +327,6 @@ class _SMFDPDOption(Schema):
327327
}))
328328
#: SMF DPD data.
329329
data: 'SMFIdentificationBasedDPDOption | SMFHashBasedDPDOption' = SwitchField(
330-
length=lambda pkt: pkt['test']['len'],
331330
selector=smf_dpd_data_selector,
332331
)
333332

@@ -367,8 +366,7 @@ class SMFIdentificationBasedDPDOption(SMFDPDOption):
367366
})
368367
#: TaggerID.
369368
tid: 'bytes | IPv4Address | IPv6Address' = ConditionalField(
370-
SwitchField(length=lambda pkt: pkt['info']['len'] + 1,
371-
selector=smf_i_dpd_tid_selector),
369+
SwitchField(selector=smf_i_dpd_tid_selector),
372370
lambda pkt: pkt['info']['type'] != 0,
373371
)
374372
#: Identifier.
@@ -449,7 +447,6 @@ class _QuickStartOption(Schema):
449447
}))
450448
#: QS data.
451449
data: 'QuickStartRequestOption | QuickStartReportOption' = SwitchField(
452-
length=5,
453450
selector=quick_start_data_selector,
454451
)
455452

pcapkit/protocols/schema/internet/ipv6_route.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,12 @@ def ipv6_route_data_selector(pkt: 'dict[str, Any]') -> 'Field':
5858
"""
5959
type = cast('Enum_Routing', pkt['type'])
6060
if type == Enum_Routing.Source_Route:
61-
return SchemaField(schema=SourceRoute)
61+
return SchemaField(length=pkt['length'] * 8 - 4, schema=SourceRoute)
6262
if type == Enum_Routing.Type_2_Routing_Header:
63-
return SchemaField(schema=Type2)
63+
return SchemaField(length=pkt['length'] * 8 - 4, schema=Type2)
6464
if type == Enum_Routing.RPL_Source_Route_Header:
65-
return SchemaField(schema=RPL)
66-
return SchemaField(schema=UnknownType)
65+
return SchemaField(length=pkt['length'] * 8 - 4, schema=RPL)
66+
return SchemaField(length=pkt['length'] * 8 - 4, schema=UnknownType)
6767

6868

6969
class IPv6_Route(Schema):
@@ -79,7 +79,6 @@ class IPv6_Route(Schema):
7979
seg_left: 'int' = UInt8Field()
8080
#: Routing data.
8181
data: 'RoutingType' = SwitchField(
82-
length=lambda pkt: pkt['length'] * 8 - 4,
8382
selector=ipv6_route_data_selector,
8483
)
8584
#: Payload.

pcapkit/protocols/schema/link/ospf.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ class OSPF(Schema):
7474
auth_type: 'Enum_Authentication' = EnumField(length=2, namespace=Enum_Authentication)
7575
#: Authentication data.
7676
auth_data: 'bytes | CrytographicAuthentication' = SwitchField(
77-
length=8,
7877
selector=ospf_auth_data_selector,
7978
)
8079
#: Payload.

0 commit comments

Comments
 (0)