@@ -19,6 +19,8 @@ import (
19
19
ipath "github.com/ipfs/boxo/coreiface/path"
20
20
cid "github.com/ipfs/go-cid"
21
21
logging "github.com/ipfs/go-log"
22
+ "github.com/libp2p/go-libp2p/core/peer"
23
+ "github.com/multiformats/go-multibase"
22
24
prometheus "github.com/prometheus/client_golang/prometheus"
23
25
"go.opentelemetry.io/otel/attribute"
24
26
"go.opentelemetry.io/otel/trace"
@@ -204,6 +206,10 @@ func (i *handler) getOrHeadHandler(w http.ResponseWriter, r *http.Request) {
204
206
return
205
207
}
206
208
209
+ if handleIpnsB58mhToCidRedirection (w , r ) {
210
+ return
211
+ }
212
+
207
213
contentPath := ipath .New (r .URL .Path )
208
214
ctx := context .WithValue (r .Context (), ContentPathKey , contentPath )
209
215
r = r .WithContext (ctx )
@@ -728,6 +734,57 @@ func handleServiceWorkerRegistration(r *http.Request) (err *ErrorResponse) {
728
734
return nil
729
735
}
730
736
737
+ // handleIpnsB58mhToCidRedirection redirects from /ipns/b58mh to /ipns/cid in
738
+ // the most cost-effective way.
739
+ func handleIpnsB58mhToCidRedirection (w http.ResponseWriter , r * http.Request ) bool {
740
+ if _ , dnslink := r .Context ().Value (DNSLinkHostnameKey ).(string ); dnslink {
741
+ // For DNSLink hostnames, do not perform redirection in order to not break
742
+ // website. For example, if `example.net` is backed by `/ipns/base58`, we
743
+ // must NOT redirect to `example.net/ipns/base36-id`.
744
+ return false
745
+ }
746
+
747
+ if w .Header ().Get ("Location" ) != "" {
748
+ // Ignore this if there is already a redirection in place. This happens
749
+ // if there is a subdomain redirection. In that case, the path is already
750
+ // converted to CIDv1.
751
+ return false
752
+ }
753
+
754
+ pathParts := strings .Split (r .URL .Path , "/" )
755
+ if len (pathParts ) < 3 {
756
+ return false
757
+ }
758
+
759
+ if pathParts [1 ] != "ipns" {
760
+ return false
761
+ }
762
+
763
+ id , err := peer .Decode (pathParts [2 ])
764
+ if err != nil {
765
+ return false
766
+ }
767
+
768
+ // Convert the peer ID to a CIDv1.
769
+ cid := peer .ToCid (id )
770
+
771
+ // Encode CID in base36 to match the subdomain URLs.
772
+ encodedCID , err := cid .StringOfBase (multibase .Base36 )
773
+ if err != nil {
774
+ return false
775
+ }
776
+
777
+ // If the CID was already encoded, do not redirect.
778
+ if encodedCID == pathParts [2 ] {
779
+ return false
780
+ }
781
+
782
+ pathParts [2 ] = encodedCID
783
+ r .URL .Path = strings .Join (pathParts , "/" )
784
+ http .Redirect (w , r , r .URL .String (), http .StatusFound )
785
+ return true
786
+ }
787
+
731
788
// Attempt to fix redundant /ipfs/ namespace as long as resulting
732
789
// 'intended' path is valid. This is in case gremlins were tickled
733
790
// wrong way and user ended up at /ipfs/ipfs/{cid} or /ipfs/ipns/{id}
0 commit comments