uri.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // Copyright 2017 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package api
  17. import (
  18. "fmt"
  19. "net/url"
  20. "regexp"
  21. "strings"
  22. "github.com/ethereum/go-ethereum/common"
  23. "github.com/ethereum/go-ethereum/swarm/storage"
  24. )
  25. //matches hex swarm hashes
  26. // TODO: this is bad, it should not be hardcoded how long is a hash
  27. var hashMatcher = regexp.MustCompile("^([0-9A-Fa-f]{64})([0-9A-Fa-f]{64})?$")
  28. // URI is a reference to content stored in swarm.
  29. type URI struct {
  30. // Scheme has one of the following values:
  31. //
  32. // * bzz - an entry in a swarm manifest
  33. // * bzz-raw - raw swarm content
  34. // * bzz-immutable - immutable URI of an entry in a swarm manifest
  35. // (address is not resolved)
  36. // * bzz-list - list of all files contained in a swarm manifest
  37. //
  38. Scheme string
  39. // Addr is either a hexadecimal storage address or it an address which
  40. // resolves to a storage address
  41. Addr string
  42. // addr stores the parsed storage address
  43. addr storage.Address
  44. // Path is the path to the content within a swarm manifest
  45. Path string
  46. }
  47. func (u *URI) MarshalJSON() (out []byte, err error) {
  48. return []byte(`"` + u.String() + `"`), nil
  49. }
  50. func (u *URI) UnmarshalJSON(value []byte) error {
  51. uri, err := Parse(string(value))
  52. if err != nil {
  53. return err
  54. }
  55. *u = *uri
  56. return nil
  57. }
  58. // Parse parses rawuri into a URI struct, where rawuri is expected to have one
  59. // of the following formats:
  60. //
  61. // * <scheme>:/
  62. // * <scheme>:/<addr>
  63. // * <scheme>:/<addr>/<path>
  64. // * <scheme>://
  65. // * <scheme>://<addr>
  66. // * <scheme>://<addr>/<path>
  67. //
  68. // with scheme one of bzz, bzz-raw, bzz-immutable, bzz-list or bzz-hash
  69. func Parse(rawuri string) (*URI, error) {
  70. u, err := url.Parse(rawuri)
  71. if err != nil {
  72. return nil, err
  73. }
  74. uri := &URI{Scheme: u.Scheme}
  75. // check the scheme is valid
  76. switch uri.Scheme {
  77. case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzz-hash", "bzz-feed":
  78. default:
  79. return nil, fmt.Errorf("unknown scheme %q", u.Scheme)
  80. }
  81. // handle URIs like bzz://<addr>/<path> where the addr and path
  82. // have already been split by url.Parse
  83. if u.Host != "" {
  84. uri.Addr = u.Host
  85. uri.Path = strings.TrimLeft(u.Path, "/")
  86. return uri, nil
  87. }
  88. // URI is like bzz:/<addr>/<path> so split the addr and path from
  89. // the raw path (which will be /<addr>/<path>)
  90. parts := strings.SplitN(strings.TrimLeft(u.Path, "/"), "/", 2)
  91. uri.Addr = parts[0]
  92. if len(parts) == 2 {
  93. uri.Path = parts[1]
  94. }
  95. return uri, nil
  96. }
  97. func (u *URI) Feed() bool {
  98. return u.Scheme == "bzz-feed"
  99. }
  100. func (u *URI) Raw() bool {
  101. return u.Scheme == "bzz-raw"
  102. }
  103. func (u *URI) Immutable() bool {
  104. return u.Scheme == "bzz-immutable"
  105. }
  106. func (u *URI) List() bool {
  107. return u.Scheme == "bzz-list"
  108. }
  109. func (u *URI) Hash() bool {
  110. return u.Scheme == "bzz-hash"
  111. }
  112. func (u *URI) String() string {
  113. return u.Scheme + ":/" + u.Addr + "/" + u.Path
  114. }
  115. func (u *URI) Address() storage.Address {
  116. if u.addr != nil {
  117. return u.addr
  118. }
  119. if hashMatcher.MatchString(u.Addr) {
  120. u.addr = common.Hex2Bytes(u.Addr)
  121. return u.addr
  122. }
  123. return nil
  124. }