@@ -18,12 +18,12 @@ import (
18
18
)
19
19
20
20
var pathGatewaySpec = config.GatewaySpec {
21
- Paths : []string {ipfsPathPrefix , ipnsPathPrefix , "/api" , "/p2p" , "/version" },
21
+ Paths : []string {"/ipfs/" , "/ipns/" , "/api/ " , "/p2p/ " , "/version" },
22
22
UseSubdomains : false ,
23
23
}
24
24
25
25
var subdomainGatewaySpec = config.GatewaySpec {
26
- Paths : []string {ipfsPathPrefix , ipnsPathPrefix },
26
+ Paths : []string {"/ipfs/" , "/ipns/" , "/api/" , "/p2p/" },
27
27
UseSubdomains : true ,
28
28
}
29
29
@@ -38,7 +38,7 @@ var defaultKnownGateways = map[string]config.GatewaySpec{
38
38
39
39
// Find content identifier, protocol, and remaining hostname (host+optional port)
40
40
// of a subdomain gateway (eg. *.ipfs.foo.bar.co.uk)
41
- var subdomainGatewayRegex = regexp .MustCompile ("^(.+).(ipfs|ipns|ipld|p2p).([^/?#&]+)$" )
41
+ var subdomainGatewayRegex = regexp .MustCompile ("^(.+).(ipfs|ipns|ipld|p2p|api ).([^/?#&]+)$" )
42
42
43
43
// HostnameOption rewrites an incoming request based on the Host header.
44
44
func HostnameOption () ServeOption {
@@ -112,7 +112,7 @@ func HostnameOption() ServeOption {
112
112
if gw .UseSubdomains {
113
113
// Yes, redirect if applicable (pretty much everything except `/api`).
114
114
// Example: dweb.link/ipfs/{cid} → {cid}.ipfs.dweb.link
115
- if newURL , ok := toSubdomainURL (r .Host , r .URL .Path ); ok {
115
+ if newURL , ok := toSubdomainURL (r .Host , r .URL .Path , r . URL . RawQuery ); ok {
116
116
http .Redirect (w , r , newURL , http .StatusMovedPermanently )
117
117
return
118
118
}
@@ -130,24 +130,24 @@ func HostnameOption() ServeOption {
130
130
131
131
// HTTP Host check: is this one of our subdomain-based "known gateways"?
132
132
// Example: {cid}.ipfs.localhost, {cid}.ipfs.dweb.link
133
- if hostname , ns , rootId , ok := parseSubdomains (r .Host ); ok {
133
+ if hostname , ns , rootID , ok := parseSubdomains (r .Host ); ok {
134
134
// Looks like we're using subdomains.
135
135
136
136
// Again, is this a known gateway that supports subdomains?
137
137
if gw , ok := isKnownGateway (hostname ); ok {
138
138
139
139
// Assemble original path prefix.
140
- pathPrefix := "/" + ns + "/" + rootId
140
+ pathPrefix := "/" + ns + "/" + rootID
141
141
142
142
// Does this gateway _handle_ this path?
143
143
if gw .UseSubdomains && hasPrefix (pathPrefix , gw .Paths ... ) {
144
144
145
145
// Do we need to fix multicodec in CID?
146
146
if ns == "ipns" {
147
- keyCid , err := cid .Decode (rootId )
147
+ keyCid , err := cid .Decode (rootID )
148
148
if err == nil && keyCid .Type () != cid .Libp2pKey {
149
149
150
- if newURL , ok := toSubdomainURL (hostname , pathPrefix + r .URL .Path ); ok {
150
+ if newURL , ok := toSubdomainURL (hostname , pathPrefix + r .URL .Path , r . URL . RawQuery ); ok {
151
151
// Redirect to CID fixed inside of toSubdomainURL()
152
152
http .Redirect (w , r , newURL , http .StatusMovedPermanently )
153
153
return
@@ -198,7 +198,7 @@ func HostnameOption() ServeOption {
198
198
199
199
func isSubdomainNamespace (ns string ) bool {
200
200
switch ns {
201
- case "ipfs" , "ipns" , "p2p" , "ipld" :
201
+ case "ipfs" , "ipns" , "p2p" , "ipld" , "api" :
202
202
return true
203
203
default :
204
204
return false
@@ -207,7 +207,7 @@ func isSubdomainNamespace(ns string) bool {
207
207
208
208
// Parses Host header of a subdomain-based URL and returns it's components
209
209
// Note: hostname is host + optional port
210
- func parseSubdomains (hostHeader string ) (hostname , ns , rootId string , ok bool ) {
210
+ func parseSubdomains (hostHeader string ) (hostname , ns , rootID string , ok bool ) {
211
211
parts := subdomainGatewayRegex .FindStringSubmatch (hostHeader )
212
212
if len (parts ) < 4 || ! isSubdomainNamespace (parts [2 ]) {
213
213
return "" , "" , "" , false
@@ -216,17 +216,17 @@ func parseSubdomains(hostHeader string) (hostname, ns, rootId string, ok bool) {
216
216
}
217
217
218
218
// Converts a hostname/path to a subdomain-based URL, if applicable.
219
- func toSubdomainURL (hostname , path string ) (url string , ok bool ) {
219
+ func toSubdomainURL (hostname , path string , query string ) (url string , ok bool ) {
220
220
parts := strings .SplitN (path , "/" , 4 )
221
221
222
- var ns , rootId , rest string
222
+ var ns , rootID , rest string
223
223
switch len (parts ) {
224
224
case 4 :
225
225
rest = parts [3 ]
226
226
fallthrough
227
227
case 3 :
228
228
ns = parts [1 ]
229
- rootId = parts [2 ]
229
+ rootID = parts [2 ]
230
230
default :
231
231
return "" , false
232
232
}
@@ -235,7 +235,26 @@ func toSubdomainURL(hostname, path string) (url string, ok bool) {
235
235
return "" , false
236
236
}
237
237
238
- if rootCid , err := cid .Decode (rootId ); err == nil {
238
+ // add prefix if query is present
239
+ if query != "" {
240
+ query = "?" + query
241
+ }
242
+
243
+ if ns == "api" || ns == "p2p" {
244
+ // API and P2P proxy use the same paths on subdomains:
245
+ // api.hostname/api/.. and p2p.hostname/p2p/..
246
+ return fmt .Sprintf (
247
+ "http://%s.%s/%s/%s/%s%s" ,
248
+ ns ,
249
+ hostname ,
250
+ ns ,
251
+ rootID ,
252
+ rest ,
253
+ query ,
254
+ ), true
255
+ }
256
+
257
+ if rootCid , err := cid .Decode (rootID ); err == nil {
239
258
multicodec := rootCid .Type ()
240
259
241
260
// CIDs in IPNS are expected to have libp2p-key multicodec.
@@ -248,15 +267,16 @@ func toSubdomainURL(hostname, path string) (url string, ok bool) {
248
267
// if object turns out to be a valid CID,
249
268
// ensure text representation used in subdomain is CIDv1 in Base32
250
269
// https://github.com/ipfs/in-web-browsers/issues/89
251
- rootId = cid .NewCidV1 (multicodec , rootCid .Hash ()).String ()
270
+ rootID = cid .NewCidV1 (multicodec , rootCid .Hash ()).String ()
252
271
}
253
272
254
273
return fmt .Sprintf (
255
- "http://%s.%s.%s/%s" ,
256
- rootId ,
274
+ "http://%s.%s.%s/%s%s " ,
275
+ rootID ,
257
276
ns ,
258
277
hostname ,
259
278
rest ,
279
+ query ,
260
280
), true
261
281
}
262
282
0 commit comments