11package multiaddr
22
33import (
4+ "bytes"
45 "encoding/binary"
56 "encoding/json"
67 "fmt"
@@ -11,9 +12,11 @@ import (
1112
1213// Component is a single multiaddr Component.
1314type Component struct {
14- bytes string // Uses the string type to ensure immutability.
15- protocol Protocol
16- offset int
15+ // bytes is the raw bytes of the component. It includes the protocol code as
16+ // varint, possibly the size of the value, and the value.
17+ bytes string // string for immutability.
18+ protocol * Protocol
19+ valueStartIdx int // Index of the first byte of the Component's value in the bytes array
1720}
1821
1922func (c Component ) AsMultiaddr () Multiaddr {
@@ -107,22 +110,31 @@ func (c Component) Compare(o Component) int {
107110}
108111
109112func (c Component ) Protocols () []Protocol {
110- return []Protocol {c .protocol }
113+ if c .protocol == nil {
114+ return nil
115+ }
116+ return []Protocol {* c .protocol }
111117}
112118
113119func (c Component ) ValueForProtocol (code int ) (string , error ) {
120+ if c .protocol == nil {
121+ return "" , fmt .Errorf ("component has nil protocol" )
122+ }
114123 if c .protocol .Code != code {
115124 return "" , ErrProtocolNotFound
116125 }
117126 return c .Value (), nil
118127}
119128
120129func (c Component ) Protocol () Protocol {
121- return c .protocol
130+ if c .protocol == nil {
131+ return Protocol {}
132+ }
133+ return * c .protocol
122134}
123135
124136func (c Component ) RawValue () []byte {
125- return []byte (c .bytes [c .offset :])
137+ return []byte (c .bytes [c .valueStartIdx :])
126138}
127139
128140func (c Component ) Value () string {
@@ -135,10 +147,13 @@ func (c Component) Value() string {
135147}
136148
137149func (c Component ) valueAndErr () (string , error ) {
150+ if c .protocol == nil {
151+ return "" , fmt .Errorf ("component has nil protocol" )
152+ }
138153 if c .protocol .Transcoder == nil {
139154 return "" , nil
140155 }
141- value , err := c .protocol .Transcoder .BytesToString ([]byte (c .bytes [c .offset :]))
156+ value , err := c .protocol .Transcoder .BytesToString ([]byte (c .bytes [c .valueStartIdx :]))
142157 if err != nil {
143158 return "" , err
144159 }
@@ -154,6 +169,9 @@ func (c Component) String() string {
154169// writeTo is an efficient, private function for string-formatting a multiaddr.
155170// Trust me, we tend to allocate a lot when doing this.
156171func (c Component ) writeTo (b * strings.Builder ) {
172+ if c .protocol == nil {
173+ return
174+ }
157175 b .WriteByte ('/' )
158176 b .WriteString (c .protocol .Name )
159177 value := c .Value ()
@@ -185,6 +203,11 @@ func NewComponent(protocol, value string) (Component, error) {
185203}
186204
187205func newComponent (protocol Protocol , bvalue []byte ) (Component , error ) {
206+ protocolPtr := protocolPtrByCode [protocol .Code ]
207+ if protocolPtr == nil {
208+ protocolPtr = & protocol
209+ }
210+
188211 size := len (bvalue )
189212 size += len (protocol .VCode )
190213 if protocol .Size < 0 {
@@ -205,23 +228,63 @@ func newComponent(protocol Protocol, bvalue []byte) (Component, error) {
205228
206229 return validateComponent (
207230 Component {
208- bytes : string (maddr ),
209- protocol : protocol ,
210- offset : offset ,
231+ bytes : string (maddr ),
232+ protocol : protocolPtr ,
233+ valueStartIdx : offset ,
211234 })
212235}
213236
214237// validateComponent MUST be called after creating a non-zero Component.
215238// It ensures that we will be able to call all methods on Component without
216239// error.
217240func validateComponent (c Component ) (Component , error ) {
241+ if c .protocol == nil {
242+ return Component {}, fmt .Errorf ("component is missing its protocol" )
243+ }
244+ if c .valueStartIdx > len (c .bytes ) {
245+ return Component {}, fmt .Errorf ("component valueStartIdx is greater than the length of the component's bytes" )
246+ }
247+
248+ if len (c .protocol .VCode ) == 0 {
249+ return Component {}, fmt .Errorf ("Component is missing its protocol's VCode field" )
250+ }
251+ if len (c .bytes ) < len (c .protocol .VCode ) {
252+ return Component {}, fmt .Errorf ("component size mismatch: %d != %d" , len (c .bytes ), len (c .protocol .VCode ))
253+ }
254+ if ! bytes .Equal ([]byte (c .bytes [:len (c .protocol .VCode )]), c .protocol .VCode ) {
255+ return Component {}, fmt .Errorf ("component's VCode field is invalid: %v != %v" , []byte (c .bytes [:len (c .protocol .VCode )]), c .protocol .VCode )
256+ }
257+ if c .protocol .Size < 0 {
258+ size , n , err := ReadVarintCode ([]byte (c .bytes [len (c .protocol .VCode ):]))
259+ if err != nil {
260+ return Component {}, err
261+ }
262+ if size != len (c .bytes [c .valueStartIdx :]) {
263+ return Component {}, fmt .Errorf ("component value size mismatch: %d != %d" , size , len (c .bytes [c .valueStartIdx :]))
264+ }
265+
266+ if len (c .protocol .VCode )+ n + size != len (c .bytes ) {
267+ return Component {}, fmt .Errorf ("component size mismatch: %d != %d" , len (c .protocol .VCode )+ n + size , len (c .bytes ))
268+ }
269+ } else {
270+ // Fixed size value
271+ size := c .protocol .Size / 8
272+ if size != len (c .bytes [c .valueStartIdx :]) {
273+ return Component {}, fmt .Errorf ("component value size mismatch: %d != %d" , size , len (c .bytes [c .valueStartIdx :]))
274+ }
275+
276+ if len (c .protocol .VCode )+ size != len (c .bytes ) {
277+ return Component {}, fmt .Errorf ("component size mismatch: %d != %d" , len (c .protocol .VCode )+ size , len (c .bytes ))
278+ }
279+ }
280+
218281 _ , err := c .valueAndErr ()
219282 if err != nil {
220283 return Component {}, err
221284
222285 }
223286 if c .protocol .Transcoder != nil {
224- err = c .protocol .Transcoder .ValidateBytes ([]byte (c .bytes [c .offset :]))
287+ err = c .protocol .Transcoder .ValidateBytes ([]byte (c .bytes [c .valueStartIdx :]))
225288 if err != nil {
226289 return Component {}, err
227290 }
0 commit comments