@@ -173,6 +173,42 @@ const (
173
173
Size1 OptionID = 60
174
174
)
175
175
176
+ // Option value format (RFC7252 section 3.2)
177
+ type valueFormat uint8
178
+
179
+ const (
180
+ valueUnknown valueFormat = iota
181
+ valueEmpty
182
+ valueOpaque
183
+ valueUint
184
+ valueString
185
+ )
186
+
187
+ type optionDef struct {
188
+ valueFormat valueFormat
189
+ minLen int
190
+ maxLen int
191
+ }
192
+
193
+ var optionDefs = [256 ]optionDef {
194
+ IfMatch : optionDef {valueFormat : valueOpaque , minLen : 0 , maxLen : 8 },
195
+ URIHost : optionDef {valueFormat : valueString , minLen : 1 , maxLen : 255 },
196
+ ETag : optionDef {valueFormat : valueOpaque , minLen : 1 , maxLen : 8 },
197
+ IfNoneMatch : optionDef {valueFormat : valueEmpty , minLen : 0 , maxLen : 0 },
198
+ Observe : optionDef {valueFormat : valueUint , minLen : 0 , maxLen : 3 },
199
+ URIPort : optionDef {valueFormat : valueUint , minLen : 0 , maxLen : 2 },
200
+ LocationPath : optionDef {valueFormat : valueString , minLen : 0 , maxLen : 255 },
201
+ URIPath : optionDef {valueFormat : valueString , minLen : 0 , maxLen : 255 },
202
+ ContentFormat : optionDef {valueFormat : valueUint , minLen : 0 , maxLen : 2 },
203
+ MaxAge : optionDef {valueFormat : valueUint , minLen : 0 , maxLen : 4 },
204
+ URIQuery : optionDef {valueFormat : valueString , minLen : 0 , maxLen : 255 },
205
+ Accept : optionDef {valueFormat : valueUint , minLen : 0 , maxLen : 2 },
206
+ LocationQuery : optionDef {valueFormat : valueString , minLen : 0 , maxLen : 255 },
207
+ ProxyURI : optionDef {valueFormat : valueString , minLen : 1 , maxLen : 1034 },
208
+ ProxyScheme : optionDef {valueFormat : valueString , minLen : 1 , maxLen : 255 },
209
+ Size1 : optionDef {valueFormat : valueUint , minLen : 0 , maxLen : 4 },
210
+ }
211
+
176
212
// MediaType specifies the content type of a message.
177
213
type MediaType byte
178
214
@@ -244,6 +280,33 @@ func (o option) toBytes() []byte {
244
280
return encodeInt (v )
245
281
}
246
282
283
+ func parseOptionValue (optionID OptionID , valueBuf []byte ) interface {} {
284
+ def := optionDefs [optionID ]
285
+ if def .valueFormat == valueUnknown {
286
+ // Skip unrecognized options (RFC7252 section 5.4.1)
287
+ return nil
288
+ }
289
+ if len (valueBuf ) < def .minLen || len (valueBuf ) > def .maxLen {
290
+ // Skip options with illegal value length (RFC7252 section 5.4.3)
291
+ return nil
292
+ }
293
+ switch def .valueFormat {
294
+ case valueUint :
295
+ intValue := decodeInt (valueBuf )
296
+ if optionID == ContentFormat || optionID == Accept {
297
+ return MediaType (intValue )
298
+ } else {
299
+ return intValue
300
+ }
301
+ case valueString :
302
+ return string (valueBuf )
303
+ case valueOpaque , valueEmpty :
304
+ return valueBuf
305
+ }
306
+ // Skip unrecognized options (should never be reached)
307
+ return nil
308
+ }
309
+
247
310
type options []option
248
311
249
312
func (o options ) Len () int {
@@ -547,27 +610,15 @@ func (m *Message) UnmarshalBinary(data []byte) error {
547
610
if len (b ) < length {
548
611
return errors .New ("truncated" )
549
612
}
550
- oid := OptionID (prev + delta )
551
613
552
- var opval interface {} = b [:length ]
553
- switch oid {
554
- case ContentFormat , Accept :
555
- opval = MediaType (decodeInt (b [:length ]))
556
- case URIPort , MaxAge , Size1 :
557
- opval = decodeInt (b [:length ])
558
- case URIHost , LocationPath , URIPath , URIQuery , LocationQuery ,
559
- ProxyURI , ProxyScheme :
560
- opval = string (b [:length ])
561
- }
562
-
563
- option := option {
564
- ID : oid ,
565
- Value : opval ,
566
- }
614
+ oid := OptionID (prev + delta )
615
+ opval := parseOptionValue (oid , b [:length ])
567
616
b = b [length :]
568
- prev = int (option . ID )
617
+ prev = int (oid )
569
618
570
- m .opts = append (m .opts , option )
619
+ if opval != nil {
620
+ m .opts = append (m .opts , option {ID : oid , Value : opval })
621
+ }
571
622
}
572
623
m .Payload = b
573
624
return nil
0 commit comments