| 1 | #!/usr/bin/env bash |
| 2 | # |
| 3 | # Copyright (c) Protocol Labs |
| 4 | |
| 5 | test_description="Test subdomain support on the HTTP gateway" |
| 6 | |
| 7 | |
| 8 | . lib/test-lib.sh |
| 9 | |
| 10 | ## ============================================================================ |
| 11 | ## Helpers specific to subdomain tests |
| 12 | ## ============================================================================ |
| 13 | |
| 14 | # Helper that tests gateway response over direct HTTP |
| 15 | # and in all supported HTTP proxy modes |
| 16 | test_localhost_gateway_response_should_contain() { |
| 17 | local label="$1" |
| 18 | local expected="$3" |
| 19 | |
| 20 | # explicit "Host: $hostname" header to match browser behavior |
| 21 | # and also make tests independent from DNS |
| 22 | local host=$(echo $2 | cut -d'/' -f3 | cut -d':' -f1) |
| 23 | local hostname=$(echo $2 | cut -d'/' -f3 | cut -d':' -f1,2) |
| 24 | |
| 25 | # Proxy is the same as HTTP Gateway, we use raw IP and port to be sure |
| 26 | local proxy="http://127.0.0.1:$GWAY_PORT" |
| 27 | |
| 28 | # Create a raw URL version with IP to ensure hostname from Host header is used |
| 29 | # (removes false-positives, Host header is used for passing hostname already) |
| 30 | local url="$2" |
| 31 | local rawurl=$(echo "$url" | sed "s/$hostname/127.0.0.1:$GWAY_PORT/") |
| 32 | |
| 33 | #echo "hostname: $hostname" |
| 34 | #echo "url before: $url" |
| 35 | #echo "url after: $rawurl" |
| 36 | |
| 37 | # regular HTTP request |
| 38 | # (hostname in Host header, raw IP in URL) |
| 39 | test_expect_success "$label (direct HTTP)" " |
| 40 | curl -H \"Host: $hostname\" -sD - \"$rawurl\" > response && |
| 41 | test_should_contain \"$expected\" response |
| 42 | " |
| 43 | |
| 44 | # HTTP proxy |
| 45 | # (hostname is passed via URL) |
| 46 | # Note: proxy client should not care, but curl does DNS lookup |
| 47 | # for some reason anyway, so we pass static DNS mapping |
| 48 | test_expect_success "$label (HTTP proxy)" " |
| 49 | curl -x $proxy --resolve $hostname:127.0.0.1 -sD - \"$url\" > response && |
| 50 | test_should_contain \"$expected\" response |
| 51 | " |
| 52 | |
| 53 | # HTTP proxy 1.0 |
| 54 | # (repeating proxy test with older spec, just to be sure) |
| 55 | test_expect_success "$label (HTTP proxy 1.0)" " |
| 56 | curl --proxy1.0 $proxy --resolve $hostname:127.0.0.1 -sD - \"$url\" > response && |
| 57 | test_should_contain \"$expected\" response |
| 58 | " |
| 59 | |
| 60 | # HTTP proxy tunneling (CONNECT) |
| 61 | # https://tools.ietf.org/html/rfc7231#section-4.3.6 |
| 62 | # In HTTP/1.x, the pseudo-method CONNECT |
| 63 | # can be used to convert an HTTP connection into a tunnel to a remote host |
| 64 | test_expect_success "$label (HTTP proxy tunneling)" " |
| 65 | curl --proxytunnel -x $proxy -H \"Host: $hostname\" -sD - \"$rawurl\" > response && |
| 66 | test_should_contain \"$expected\" response |
| 67 | " |
| 68 | } |
| 69 | |
| 70 | # Helper that checks gateway response for specific hostname in Host header |
| 71 | test_hostname_gateway_response_should_contain() { |
| 72 | local label="$1" |
| 73 | local hostname="$2" |
| 74 | local url="$3" |
| 75 | local rawurl=$(echo "$url" | sed "s/$hostname/127.0.0.1:$GWAY_PORT/") |
| 76 | local expected="$4" |
| 77 | test_expect_success "$label" " |
| 78 | curl -H \"Host: $hostname\" -sD - \"$rawurl\" > response && |
| 79 | test_should_contain \"$expected\" response |
| 80 | " |
| 81 | } |
| 82 | |
| 83 | ## ============================================================================ |
| 84 | ## Start IPFS Node and prepare test CIDs |
| 85 | ## ============================================================================ |
| 86 | |
| 87 | test_expect_success "ipfs init" ' |
| 88 | export IPFS_PATH="$(pwd)/.ipfs" && |
| 89 | ipfs init --profile=test > /dev/null |
| 90 | ' |
| 91 | |
| 92 | test_launch_ipfs_daemon_without_network |
| 93 | |
| 94 | # Import test case |
| 95 | # See the static fixtures in ./t0114-gateway-subdomains/ |
| 96 | CID_VAL=hello |
| 97 | CIDv1=bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am |
| 98 | CIDv0=QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN |
| 99 | CIDv0to1=bafybeiffndsajwhk3lwjewwdxqntmjm4b5wxaaanokonsggenkbw6slwk4 |
| 100 | CIDv1_TOO_LONG=bafkrgqhhyivzstcz3hhswshfjgy6ertgmnqeleynhwt4dlfsthi4hn7zgh4uvlsb5xncykzapi3ocd4lzogukir6ksdy6wzrnz6ohnv4aglcs |
| 101 | DIR_CID=bafybeiht6dtwk3les7vqm6ibpvz6qpohidvlshsfyr7l5mpysdw2vmbbhe |
| 102 | |
| 103 | RSA_KEY=QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3 |
| 104 | RSA_IPNS_IDv0=QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3 |
| 105 | RSA_IPNS_IDv1=k2k4r8m7xvggw5pxxk3abrkwyer625hg01hfyggrai7lk1m63fuihi7w |
| 106 | RSA_IPNS_IDv1_DAGPB=k2jmtxu61bnhrtj301lw7zizknztocdbeqhxgv76l2q9t36fn9jbzipo |
| 107 | |
| 108 | ED25519_KEY=12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d |
| 109 | ED25519_IPNS_IDv0=12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d |
| 110 | ED25519_IPNS_IDv1=k51qzi5uqu5dk3v4rmjber23h16xnr23bsggmqqil9z2gduiis5se8dht36dam |
| 111 | ED25519_IPNS_IDv1_DAGPB=k50rm9yjlt0jey4fqg6wafvqprktgbkpgkqdg27tpqje6iimzxewnhvtin9hhq |
| 112 | IPNS_ED25519_B58MH=12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d |
| 113 | IPNS_ED25519_B36CID=k51qzi5uqu5dk3v4rmjber23h16xnr23bsggmqqil9z2gduiis5se8dht36dam |
| 114 | |
| 115 | test_expect_success "Add the test fixtures" ' |
| 116 | ipfs dag import --pin-roots ../t0114-gateway-subdomains/fixtures.car && |
| 117 | ipfs routing put --allow-offline /ipns/${RSA_KEY} ../t0114-gateway-subdomains/${RSA_KEY}.ipns-record && |
| 118 | ipfs routing put --allow-offline /ipns/${ED25519_KEY} ../t0114-gateway-subdomains/${ED25519_KEY}.ipns-record |
| 119 | ' |
| 120 | |
| 121 | # ensure we start with empty Gateway.PublicGateways |
| 122 | test_expect_success 'start daemon with empty config for Gateway.PublicGateways' ' |
| 123 | test_kill_ipfs_daemon && |
| 124 | ipfs config --json Gateway.PublicGateways "{}" && |
| 125 | test_launch_ipfs_daemon_without_network |
| 126 | ' |
| 127 | |
| 128 | ## ============================================================================ |
| 129 | ## Test path-based requests to a local gateway with default config |
| 130 | ## (forced redirects to http://*.localhost) |
| 131 | ## ============================================================================ |
| 132 | |
| 133 | # /ipfs/<cid> |
| 134 | |
| 135 | # IP remains old school path-based gateway |
| 136 | |
| 137 | test_localhost_gateway_response_should_contain \ |
| 138 | "request for 127.0.0.1/ipfs/{CID} stays on path" \ |
| 139 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1" \ |
| 140 | "$CID_VAL" |
| 141 | |
| 142 | # 'localhost' hostname is used for subdomains, and should not return |
| 143 | # payload directly, but redirect to URL with proper origin isolation |
| 144 | |
| 145 | test_localhost_gateway_response_should_contain \ |
| 146 | "request for localhost/ipfs/{CIDv1} returns HTTP 301 Moved Permanently" \ |
| 147 | "http://localhost:$GWAY_PORT/ipfs/$CIDv1" \ |
| 148 | "301 Moved Permanently" |
| 149 | |
| 150 | test_localhost_gateway_response_should_contain \ |
| 151 | "request for localhost/ipfs/{CIDv1} returns Location HTTP header for subdomain redirect in browsers" \ |
| 152 | "http://localhost:$GWAY_PORT/ipfs/$CIDv1" \ |
| 153 | "Location: http://$CIDv1.ipfs.localhost:$GWAY_PORT/" |
| 154 | |
| 155 | test_localhost_gateway_response_should_contain \ |
| 156 | "request for localhost/ipfs/{DIR_CID} returns HTTP 301 Moved Permanently" \ |
| 157 | "http://localhost:$GWAY_PORT/ipfs/$DIR_CID" \ |
| 158 | "301 Moved Permanently" |
| 159 | |
| 160 | test_localhost_gateway_response_should_contain \ |
| 161 | "request for localhost/ipfs/{DIR_CID} returns Location HTTP header for subdomain redirect in browsers" \ |
| 162 | "http://localhost:$GWAY_PORT/ipfs/$DIR_CID/" \ |
| 163 | "Location: http://$DIR_CID.ipfs.localhost:$GWAY_PORT/" |
| 164 | |
| 165 | # Kubo specific end-to-end test |
| 166 | # (independent of gateway-conformance) |
| 167 | |
| 168 | # We return human-readable body with HTTP 301 so existing cli scripts that use path-based |
| 169 | # gateway are informed to enable following HTTP redirects |
| 170 | test_localhost_gateway_response_should_contain \ |
| 171 | "request for localhost/ipfs/{CIDv1} includes human-readable link and redirect info in HTTP 301 body" \ |
| 172 | "http://localhost:$GWAY_PORT/ipfs/$CIDv1" \ |
| 173 | ">Moved Permanently</a>" |
| 174 | |
| 175 | # end Kubo specific end-to-end test |
| 176 | |
| 177 | test_localhost_gateway_response_should_contain \ |
| 178 | "request for localhost/ipfs/{CIDv0} redirects to CIDv1 representation in subdomain" \ |
| 179 | "http://localhost:$GWAY_PORT/ipfs/$CIDv0" \ |
| 180 | "Location: http://${CIDv0to1}.ipfs.localhost:$GWAY_PORT/" |
| 181 | |
| 182 | # /ipns/<libp2p-key> |
| 183 | |
| 184 | test_localhost_gateway_response_should_contain \ |
| 185 | "request for localhost/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ |
| 186 | "http://localhost:$GWAY_PORT/ipns/$RSA_IPNS_IDv0" \ |
| 187 | "Location: http://${RSA_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" |
| 188 | |
| 189 | test_localhost_gateway_response_should_contain \ |
| 190 | "request for localhost/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ |
| 191 | "http://localhost:$GWAY_PORT/ipns/$ED25519_IPNS_IDv0" \ |
| 192 | "Location: http://${ED25519_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" |
| 193 | |
| 194 | # /ipns/<dnslink-fqdn> |
| 195 | |
| 196 | # Kubo specific end-to-end test |
| 197 | # (independent of gateway-conformance) |
| 198 | |
| 199 | test_localhost_gateway_response_should_contain \ |
| 200 | "request for localhost/ipns/{fqdn} redirects to DNSLink in subdomain" \ |
| 201 | "http://localhost:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki" \ |
| 202 | "Location: http://en.wikipedia-on-ipfs.org.ipns.localhost:$GWAY_PORT/wiki" |
| 203 | |
| 204 | # end Kubo specific end-to-end test |
| 205 | |
| 206 | ## ============================================================================ |
| 207 | ## Test subdomain-based requests to a local gateway with default config |
| 208 | ## (origin per content root at http://*.localhost) |
| 209 | ## ============================================================================ |
| 210 | |
| 211 | # {CID}.ipfs.localhost |
| 212 | |
| 213 | test_localhost_gateway_response_should_contain \ |
| 214 | "request for {CID}.ipfs.localhost should return expected payload" \ |
| 215 | "http://${CIDv1}.ipfs.localhost:$GWAY_PORT" \ |
| 216 | "$CID_VAL" |
| 217 | |
| 218 | # ensure /ipfs/ namespace is not mounted on subdomain |
| 219 | test_localhost_gateway_response_should_contain \ |
| 220 | "request for {CID}.ipfs.localhost/ipfs/{CID} should return HTTP 404" \ |
| 221 | "http://${CIDv1}.ipfs.localhost:$GWAY_PORT/ipfs/$CIDv1" \ |
| 222 | "404 Not Found" |
| 223 | |
| 224 | # ensure requests to /ipfs/* are not blocked, if content root has such subdirectory |
| 225 | test_localhost_gateway_response_should_contain \ |
| 226 | "request for {CID}.ipfs.localhost/ipfs/file.txt should return data from a file in CID content root" \ |
| 227 | "http://${DIR_CID}.ipfs.localhost:$GWAY_PORT/ipfs/file.txt" \ |
| 228 | "I am a txt file" |
| 229 | |
| 230 | # Kubo specific end-to-end test |
| 231 | # (independent of gateway-conformance) |
| 232 | # This tests link to parent specific to boxo + relative pathing end-to-end tests specific to Kubo. |
| 233 | |
| 234 | # {CID}.ipfs.localhost/sub/dir (Directory Listing) |
| 235 | DIR_HOSTNAME="${DIR_CID}.ipfs.localhost:$GWAY_PORT" |
| 236 | |
| 237 | test_expect_success "valid file and subdirectory paths in directory listing at {cid}.ipfs.localhost" ' |
| 238 | curl -s --resolve $DIR_HOSTNAME:127.0.0.1 "http://$DIR_HOSTNAME" > list_response && |
| 239 | test_should_contain "<a href=\"/hello\">hello</a>" list_response && |
| 240 | test_should_contain "<a href=\"/ipfs\">ipfs</a>" list_response |
| 241 | ' |
| 242 | |
| 243 | test_expect_success "valid parent directory path in directory listing at {cid}.ipfs.localhost/sub/dir" ' |
| 244 | curl -s --resolve $DIR_HOSTNAME:127.0.0.1 "http://$DIR_HOSTNAME/ipfs/ipns/" > list_response && |
| 245 | test_should_contain "<a href=\"/ipfs/ipns/..\">..</a>" list_response && |
| 246 | test_should_contain "<a href=\"/ipfs/ipns/bar\">bar</a>" list_response |
| 247 | ' |
| 248 | |
| 249 | test_expect_success "request for deep path resource at {cid}.ipfs.localhost/sub/dir/file" ' |
| 250 | curl -s --resolve $DIR_HOSTNAME:127.0.0.1 "http://$DIR_HOSTNAME/ipfs/ipns/bar" > list_response && |
| 251 | test_should_contain "text-file-content" list_response |
| 252 | ' |
| 253 | # end Kubo specific end-to-end test |
| 254 | |
| 255 | # *.ipns.localhost |
| 256 | |
| 257 | # <libp2p-key>.ipns.localhost |
| 258 | |
| 259 | test_localhost_gateway_response_should_contain \ |
| 260 | "request for {CIDv1-libp2p-key}.ipns.localhost returns expected payload" \ |
| 261 | "http://${RSA_IPNS_IDv1}.ipns.localhost:$GWAY_PORT" \ |
| 262 | "$CID_VAL" |
| 263 | |
| 264 | test_localhost_gateway_response_should_contain \ |
| 265 | "request for {CIDv1-libp2p-key}.ipns.localhost returns expected payload" \ |
| 266 | "http://${ED25519_IPNS_IDv1}.ipns.localhost:$GWAY_PORT" \ |
| 267 | "$CID_VAL" |
| 268 | |
| 269 | test_localhost_gateway_response_should_contain \ |
| 270 | "localhost request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ |
| 271 | "http://${RSA_IPNS_IDv1_DAGPB}.ipns.localhost:$GWAY_PORT" \ |
| 272 | "Location: http://${RSA_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" |
| 273 | |
| 274 | test_localhost_gateway_response_should_contain \ |
| 275 | "localhost request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ |
| 276 | "http://${ED25519_IPNS_IDv1_DAGPB}.ipns.localhost:$GWAY_PORT" \ |
| 277 | "Location: http://${ED25519_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" |
| 278 | |
| 279 | # <dnslink-fqdn>.ipns.localhost |
| 280 | |
| 281 | # DNSLink test requires a daemon in online mode with precached /ipns/ mapping |
| 282 | test_kill_ipfs_daemon |
| 283 | DNSLINK_FQDN="dnslink-test.example.com" |
| 284 | export IPFS_NS_MAP="$DNSLINK_FQDN:/ipfs/$CIDv1" |
| 285 | test_launch_ipfs_daemon |
| 286 | |
| 287 | test_localhost_gateway_response_should_contain \ |
| 288 | "request for {dnslink}.ipns.localhost returns expected payload" \ |
| 289 | "http://$DNSLINK_FQDN.ipns.localhost:$GWAY_PORT" \ |
| 290 | "$CID_VAL" |
| 291 | |
| 292 | ## ============================================================================ |
| 293 | ## Test DNSLink inlining on HTTP gateways |
| 294 | ## ============================================================================ |
| 295 | |
| 296 | # set explicit subdomain gateway config for the hostname |
| 297 | ipfs config --json Gateway.PublicGateways '{ |
| 298 | "localhost": { |
| 299 | "UseSubdomains": true, |
| 300 | "InlineDNSLink": true, |
| 301 | "Paths": ["/ipfs", "/ipns", "/api"] |
| 302 | }, |
| 303 | "example.com": { |
| 304 | "UseSubdomains": true, |
| 305 | "InlineDNSLink": true, |
| 306 | "Paths": ["/ipfs", "/ipns", "/api"] |
| 307 | } |
| 308 | }' || exit 1 |
| 309 | # restart daemon to apply config changes |
| 310 | test_kill_ipfs_daemon |
| 311 | test_launch_ipfs_daemon_without_network |
| 312 | |
| 313 | test_localhost_gateway_response_should_contain \ |
| 314 | "request for localhost/ipns/{fqdn} redirects to DNSLink in subdomain with DNS inlining" \ |
| 315 | "http://localhost:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki" \ |
| 316 | "Location: http://en-wikipedia--on--ipfs-org.ipns.localhost:$GWAY_PORT/wiki" |
| 317 | |
| 318 | test_hostname_gateway_response_should_contain \ |
| 319 | "request for example.com/ipns/{fqdn} redirects to DNSLink in subdomain with DNS inlining" \ |
| 320 | "example.com" \ |
| 321 | "http://127.0.0.1:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki" \ |
| 322 | "Location: http://en-wikipedia--on--ipfs-org.ipns.example.com/wiki" |
| 323 | |
| 324 | ## ============================================================================ |
| 325 | ## Test subdomain-based requests with a custom hostname config |
| 326 | ## (origin per content root at http://*.example.com) |
| 327 | ## ============================================================================ |
| 328 | |
| 329 | # set explicit subdomain gateway config for the hostname |
| 330 | ipfs config --json Gateway.PublicGateways '{ |
| 331 | "example.com": { |
| 332 | "UseSubdomains": true, |
| 333 | "Paths": ["/ipfs", "/ipns", "/api"] |
| 334 | } |
| 335 | }' || exit 1 |
| 336 | # restart daemon to apply config changes |
| 337 | test_kill_ipfs_daemon |
| 338 | test_launch_ipfs_daemon_without_network |
| 339 | |
| 340 | |
| 341 | # example.com/ip(f|n)s/* |
| 342 | # ============================================================================= |
| 343 | |
| 344 | # path requests to the root hostname should redirect |
| 345 | # to a subdomain URL with proper origin isolation |
| 346 | |
| 347 | test_hostname_gateway_response_should_contain \ |
| 348 | "request for example.com/ipfs/{CIDv1} produces redirect to {CIDv1}.ipfs.example.com" \ |
| 349 | "example.com" \ |
| 350 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1" \ |
| 351 | "Location: http://$CIDv1.ipfs.example.com/" |
| 352 | |
| 353 | # error message should include original CID |
| 354 | # (and it should be case-sensitive, as we can't assume everyone uses base32) |
| 355 | test_hostname_gateway_response_should_contain \ |
| 356 | "request for example.com/ipfs/{InvalidCID} produces useful error before redirect" \ |
| 357 | "example.com" \ |
| 358 | "http://127.0.0.1:$GWAY_PORT/ipfs/QmInvalidCID" \ |
| 359 | 'invalid path \"/ipfs/QmInvalidCID\"' |
| 360 | |
| 361 | test_hostname_gateway_response_should_contain \ |
| 362 | "request for example.com/ipfs/{CIDv0} produces redirect to {CIDv1}.ipfs.example.com" \ |
| 363 | "example.com" \ |
| 364 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv0" \ |
| 365 | "Location: http://${CIDv0to1}.ipfs.example.com/" |
| 366 | |
| 367 | # Support X-Forwarded-Proto |
| 368 | test_expect_success "request for http://example.com/ipfs/{CID} with X-Forwarded-Proto: https produces redirect to HTTPS URL" " |
| 369 | curl -H \"X-Forwarded-Proto: https\" -H \"Host: example.com\" -sD - \"http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1\" > response && |
| 370 | test_should_contain \"Location: https://$CIDv1.ipfs.example.com/\" response |
| 371 | " |
| 372 | |
| 373 | # Support ipfs:// in https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler |
| 374 | test_hostname_gateway_response_should_contain \ |
| 375 | "request for example.com/ipfs/?uri=ipfs%3A%2F%2F.. produces redirect to /ipfs/.. content path" \ |
| 376 | "example.com" \ |
| 377 | "http://127.0.0.1:$GWAY_PORT/ipfs/?uri=ipfs%3A%2F%2FQmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco%2Fwiki%2FDiego_Maradona.html" \ |
| 378 | "Location: /ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco/wiki/Diego_Maradona.html" |
| 379 | |
| 380 | # example.com/ipns/<libp2p-key> |
| 381 | |
| 382 | test_hostname_gateway_response_should_contain \ |
| 383 | "request for example.com/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ |
| 384 | "example.com" \ |
| 385 | "http://127.0.0.1:$GWAY_PORT/ipns/$RSA_IPNS_IDv0" \ |
| 386 | "Location: http://${RSA_IPNS_IDv1}.ipns.example.com/" |
| 387 | |
| 388 | test_hostname_gateway_response_should_contain \ |
| 389 | "request for example.com/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ |
| 390 | "example.com" \ |
| 391 | "http://127.0.0.1:$GWAY_PORT/ipns/$ED25519_IPNS_IDv0" \ |
| 392 | "Location: http://${ED25519_IPNS_IDv1}.ipns.example.com/" |
| 393 | |
| 394 | # example.com/ipns/<dnslink-fqdn> |
| 395 | |
| 396 | test_hostname_gateway_response_should_contain \ |
| 397 | "request for example.com/ipns/{fqdn} redirects to DNSLink in subdomain" \ |
| 398 | "example.com" \ |
| 399 | "http://127.0.0.1:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki" \ |
| 400 | "Location: http://en.wikipedia-on-ipfs.org.ipns.example.com/wiki" |
| 401 | |
| 402 | # DNSLink on Public gateway with a single-level wildcard TLS cert |
| 403 | # "Option C" from https://github.com/ipfs/in-web-browsers/issues/169 |
| 404 | test_expect_success \ |
| 405 | "request for example.com/ipns/{fqdn} with X-Forwarded-Proto redirects to TLS-safe label in subdomain" " |
| 406 | curl -H \"Host: example.com\" -H \"X-Forwarded-Proto: https\" -sD - \"http://127.0.0.1:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki\" > response && |
| 407 | test_should_contain \"Location: https://en-wikipedia--on--ipfs-org.ipns.example.com/wiki\" response |
| 408 | " |
| 409 | |
| 410 | # Support ipns:// in https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler |
| 411 | test_hostname_gateway_response_should_contain \ |
| 412 | "request for example.com/ipns/?uri=ipns%3A%2F%2F.. produces redirect to /ipns/.. content path" \ |
| 413 | "example.com" \ |
| 414 | "http://127.0.0.1:$GWAY_PORT/ipns/?uri=ipns%3A%2F%2Fen.wikipedia-on-ipfs.org" \ |
| 415 | "Location: /ipns/en.wikipedia-on-ipfs.org" |
| 416 | |
| 417 | # *.ipfs.example.com: subdomain requests made with custom FQDN in Host header |
| 418 | |
| 419 | test_hostname_gateway_response_should_contain \ |
| 420 | "request for {CID}.ipfs.example.com should return expected payload" \ |
| 421 | "${CIDv1}.ipfs.example.com" \ |
| 422 | "http://127.0.0.1:$GWAY_PORT/" \ |
| 423 | "$CID_VAL" |
| 424 | |
| 425 | test_hostname_gateway_response_should_contain \ |
| 426 | "request for {CID}.ipfs.example.com/ipfs/{CID} should return HTTP 404" \ |
| 427 | "${CIDv1}.ipfs.example.com" \ |
| 428 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1" \ |
| 429 | "404 Not Found" |
| 430 | |
| 431 | # Kubo specific end-to-end test |
| 432 | # (independent of gateway-conformance) |
| 433 | # HTML specific to Boxo/Kubo, and relative pathing specific to code in Kubo |
| 434 | |
| 435 | # {CID}.ipfs.example.com/sub/dir (Directory Listing) |
| 436 | DIR_FQDN="${DIR_CID}.ipfs.example.com" |
| 437 | |
| 438 | test_expect_success "valid file and directory paths in directory listing at {cid}.ipfs.example.com" ' |
| 439 | curl -s -H "Host: $DIR_FQDN" http://127.0.0.1:$GWAY_PORT > list_response && |
| 440 | test_should_contain "<a href=\"/hello\">hello</a>" list_response && |
| 441 | test_should_contain "<a href=\"/ipfs\">ipfs</a>" list_response |
| 442 | ' |
| 443 | |
| 444 | test_expect_success "valid parent directory path in directory listing at {cid}.ipfs.example.com/sub/dir" ' |
| 445 | curl -s -H "Host: $DIR_FQDN" http://127.0.0.1:$GWAY_PORT/ipfs/ipns/ > list_response && |
| 446 | test_should_contain "<a href=\"/ipfs/ipns/..\">..</a>" list_response && |
| 447 | test_should_contain "<a href=\"/ipfs/ipns/bar\">bar</a>" list_response |
| 448 | ' |
| 449 | |
| 450 | # Note 1: we test for sneaky subdir names {cid}.ipfs.example.com/ipfs/ipns/ :^) |
| 451 | # Note 2: example.com/ipfs/.. present in HTML will be redirected to subdomain, so this is expected behavior |
| 452 | test_expect_success "valid breadcrumb links in the header of directory listing at {cid}.ipfs.example.com/sub/dir" ' |
| 453 | curl -s -H "Host: $DIR_FQDN" http://127.0.0.1:$GWAY_PORT/ipfs/ipns/ > list_response && |
| 454 | test_should_contain "Index of" list_response && |
| 455 | test_should_contain "/ipfs/<a href=\"//example.com/ipfs/${DIR_CID}\">${DIR_CID}</a>/<a href=\"//example.com/ipfs/${DIR_CID}/ipfs\">ipfs</a>/<a href=\"//example.com/ipfs/${DIR_CID}/ipfs/ipns\">ipns</a>" list_response |
| 456 | ' |
| 457 | |
| 458 | # end Kubo specific end-to-end test |
| 459 | |
| 460 | test_expect_success "request for deep path resource {cid}.ipfs.example.com/sub/dir/file" ' |
| 461 | curl -s -H "Host: $DIR_FQDN" http://127.0.0.1:$GWAY_PORT/ipfs/ipns/bar > list_response && |
| 462 | test_should_contain "text-file-content" list_response |
| 463 | ' |
| 464 | |
| 465 | # *.ipns.example.com |
| 466 | # ============================================================================ |
| 467 | |
| 468 | # <libp2p-key>.ipns.example.com |
| 469 | |
| 470 | test_hostname_gateway_response_should_contain \ |
| 471 | "request for {CIDv1-libp2p-key}.ipns.example.com returns expected payload" \ |
| 472 | "${RSA_IPNS_IDv1}.ipns.example.com" \ |
| 473 | "http://127.0.0.1:$GWAY_PORT" \ |
| 474 | "$CID_VAL" |
| 475 | |
| 476 | test_hostname_gateway_response_should_contain \ |
| 477 | "request for {CIDv1-libp2p-key}.ipns.example.com returns expected payload" \ |
| 478 | "${ED25519_IPNS_IDv1}.ipns.example.com" \ |
| 479 | "http://127.0.0.1:$GWAY_PORT" \ |
| 480 | "$CID_VAL" |
| 481 | |
| 482 | test_hostname_gateway_response_should_contain \ |
| 483 | "hostname request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ |
| 484 | "${RSA_IPNS_IDv1_DAGPB}.ipns.example.com" \ |
| 485 | "http://127.0.0.1:$GWAY_PORT" \ |
| 486 | "Location: http://${RSA_IPNS_IDv1}.ipns.example.com/" |
| 487 | |
| 488 | test_hostname_gateway_response_should_contain \ |
| 489 | "hostname request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ |
| 490 | "${ED25519_IPNS_IDv1_DAGPB}.ipns.example.com" \ |
| 491 | "http://127.0.0.1:$GWAY_PORT" \ |
| 492 | "Location: http://${ED25519_IPNS_IDv1}.ipns.example.com/" |
| 493 | |
| 494 | # DNSLink: <dnslink-fqdn>.ipns.example.com |
| 495 | # (not really useful outside of localhost, as setting TLS for more than one |
| 496 | # level of wildcard is a pain, but we support it if someone really wants it) |
| 497 | # ============================================================================ |
| 498 | |
| 499 | # DNSLink test requires a daemon in online mode with precached /ipns/ mapping |
| 500 | test_kill_ipfs_daemon |
| 501 | DNSLINK_FQDN="dnslink-subdomain-gw-test.example.org" |
| 502 | export IPFS_NS_MAP="$DNSLINK_FQDN:/ipfs/$CIDv1" |
| 503 | test_launch_ipfs_daemon |
| 504 | |
| 505 | test_hostname_gateway_response_should_contain \ |
| 506 | "request for {dnslink}.ipns.example.com returns expected payload" \ |
| 507 | "$DNSLINK_FQDN.ipns.example.com" \ |
| 508 | "http://127.0.0.1:$GWAY_PORT" \ |
| 509 | "$CID_VAL" |
| 510 | |
| 511 | # DNSLink on Public gateway with a single-level wildcard TLS cert |
| 512 | # "Option C" from https://github.com/ipfs/in-web-browsers/issues/169 |
| 513 | test_expect_success \ |
| 514 | "request for {single-label-dnslink}.ipns.example.com with X-Forwarded-Proto returns expected payload" " |
| 515 | curl -H \"Host: dnslink--subdomain--gw--test-example-org.ipns.example.com\" -H \"X-Forwarded-Proto: https\" -sD - \"http://127.0.0.1:$GWAY_PORT\" > response && |
| 516 | test_should_contain \"$CID_VAL\" response |
| 517 | " |
| 518 | |
| 519 | ## Test subdomain handling of CIDs that do not fit in a single DNS Label (>63chars) |
| 520 | ## https://github.com/ipfs/go-ipfs/issues/7318 |
| 521 | ## ============================================================================ |
| 522 | |
| 523 | # local: *.localhost |
| 524 | test_localhost_gateway_response_should_contain \ |
| 525 | "request for a ED25519 libp2p-key at localhost/ipns/{b58mh} returns Location HTTP header for DNS-safe subdomain redirect in browsers" \ |
| 526 | "http://localhost:$GWAY_PORT/ipns/$IPNS_ED25519_B58MH" \ |
| 527 | "Location: http://${IPNS_ED25519_B36CID}.ipns.localhost:$GWAY_PORT/" |
| 528 | |
| 529 | # router should not redirect to hostnames that could fail due to DNS limits |
| 530 | test_localhost_gateway_response_should_contain \ |
| 531 | "request for a too long CID at localhost/ipfs/{CIDv1} returns human readable error" \ |
| 532 | "http://localhost:$GWAY_PORT/ipfs/$CIDv1_TOO_LONG" \ |
| 533 | "CID incompatible with DNS label length limit of 63" |
| 534 | |
| 535 | test_localhost_gateway_response_should_contain \ |
| 536 | "request for a too long CID at localhost/ipfs/{CIDv1} returns HTTP Error 400 Bad Request" \ |
| 537 | "http://localhost:$GWAY_PORT/ipfs/$CIDv1_TOO_LONG" \ |
| 538 | "400 Bad Request" |
| 539 | |
| 540 | # direct request should also fail (provides the same UX as router and avoids confusion) |
| 541 | test_localhost_gateway_response_should_contain \ |
| 542 | "request for a too long CID at {CIDv1}.ipfs.localhost returns expected payload" \ |
| 543 | "http://$CIDv1_TOO_LONG.ipfs.localhost:$GWAY_PORT" \ |
| 544 | "400 Bad Request" |
| 545 | |
| 546 | # public subdomain gateway: *.example.com |
| 547 | |
| 548 | test_hostname_gateway_response_should_contain \ |
| 549 | "request for a ED25519 libp2p-key at example.com/ipns/{b58mh} returns Location HTTP header for DNS-safe subdomain redirect in browsers" \ |
| 550 | "example.com" \ |
| 551 | "http://127.0.0.1:$GWAY_PORT/ipns/$IPNS_ED25519_B58MH" \ |
| 552 | "Location: http://${IPNS_ED25519_B36CID}.ipns.example.com" |
| 553 | |
| 554 | test_hostname_gateway_response_should_contain \ |
| 555 | "request for a too long CID at example.com/ipfs/{CIDv1} returns human readable error" \ |
| 556 | "example.com" \ |
| 557 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1_TOO_LONG" \ |
| 558 | "CID incompatible with DNS label length limit of 63" |
| 559 | |
| 560 | test_hostname_gateway_response_should_contain \ |
| 561 | "request for a too long CID at example.com/ipfs/{CIDv1} returns HTTP Error 400 Bad Request" \ |
| 562 | "example.com" \ |
| 563 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1_TOO_LONG" \ |
| 564 | "400 Bad Request" |
| 565 | |
| 566 | test_hostname_gateway_response_should_contain \ |
| 567 | "request for a too long CID at {CIDv1}.ipfs.example.com returns HTTP Error 400 Bad Request" \ |
| 568 | "$CIDv1_TOO_LONG.ipfs.example.com" \ |
| 569 | "http://127.0.0.1:$GWAY_PORT/" \ |
| 570 | "400 Bad Request" |
| 571 | |
| 572 | # Disable selected Paths for the subdomain gateway hostname |
| 573 | # ============================================================================= |
| 574 | |
| 575 | # disable /ipns for the hostname by not whitelisting it |
| 576 | ipfs config --json Gateway.PublicGateways '{ |
| 577 | "example.com": { |
| 578 | "UseSubdomains": true, |
| 579 | "Paths": ["/ipfs"] |
| 580 | } |
| 581 | }' || exit 1 |
| 582 | # restart daemon to apply config changes |
| 583 | test_kill_ipfs_daemon |
| 584 | test_launch_ipfs_daemon_without_network |
| 585 | |
| 586 | # refuse requests to Paths that were not explicitly whitelisted for the hostname |
| 587 | test_hostname_gateway_response_should_contain \ |
| 588 | "request for *.ipns.example.com returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ |
| 589 | "${RSA_IPNS_IDv1}.ipns.example.com" \ |
| 590 | "http://127.0.0.1:$GWAY_PORT" \ |
| 591 | "404 Not Found" |
| 592 | |
| 593 | test_hostname_gateway_response_should_contain \ |
| 594 | "request for *.ipns.example.com returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ |
| 595 | "${ED25519_IPNS_IDv1}.ipns.example.com" \ |
| 596 | "http://127.0.0.1:$GWAY_PORT" \ |
| 597 | "404 Not Found" |
| 598 | |
| 599 | ## ============================================================================ |
| 600 | ## Test path-based requests with a custom hostname config |
| 601 | ## ============================================================================ |
| 602 | |
| 603 | # set explicit no-subdomain gateway config for the hostname |
| 604 | ipfs config --json Gateway.PublicGateways '{ |
| 605 | "example.com": { |
| 606 | "UseSubdomains": false, |
| 607 | "Paths": ["/ipfs"] |
| 608 | } |
| 609 | }' || exit 1 |
| 610 | |
| 611 | # restart daemon to apply config changes |
| 612 | test_kill_ipfs_daemon |
| 613 | test_launch_ipfs_daemon_without_network |
| 614 | |
| 615 | # example.com/ip(f|n)s/* smoke-tests |
| 616 | # ============================================================================= |
| 617 | |
| 618 | # confirm path gateway works for /ipfs |
| 619 | test_hostname_gateway_response_should_contain \ |
| 620 | "request for example.com/ipfs/{CIDv1} returns expected payload" \ |
| 621 | "example.com" \ |
| 622 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1" \ |
| 623 | "$CID_VAL" |
| 624 | |
| 625 | # refuse subdomain requests on path gateway |
| 626 | # (we don't want false sense of security) |
| 627 | test_hostname_gateway_response_should_contain \ |
| 628 | "request for {CID}.ipfs.example.com/ipfs/{CID} should return HTTP 404 Not Found" \ |
| 629 | "${CIDv1}.ipfs.example.com" \ |
| 630 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1" \ |
| 631 | "404 Not Found" |
| 632 | |
| 633 | # refuse requests to Paths that were not explicitly whitelisted for the hostname |
| 634 | test_hostname_gateway_response_should_contain \ |
| 635 | "request for example.com/ipns/ returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ |
| 636 | "example.com" \ |
| 637 | "http://127.0.0.1:$GWAY_PORT/ipns/$RSA_IPNS_IDv1" \ |
| 638 | "404 Not Found" |
| 639 | |
| 640 | test_hostname_gateway_response_should_contain \ |
| 641 | "request for example.com/ipns/ returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ |
| 642 | "example.com" \ |
| 643 | "http://127.0.0.1:$GWAY_PORT/ipns/$ED25519_IPNS_IDv1" \ |
| 644 | "404 Not Found" |
| 645 | |
| 646 | ## ============================================================================ |
| 647 | ## Test DNSLink requests with a custom PublicGateway (hostname config) |
| 648 | ## (DNSLink site at http://dnslink-test.example.com) |
| 649 | ## ============================================================================ |
| 650 | |
| 651 | test_kill_ipfs_daemon |
| 652 | |
| 653 | # disable wildcard DNSLink gateway |
| 654 | # and enable it on specific NSLink hostname |
| 655 | ipfs config --json Gateway.NoDNSLink true && \ |
| 656 | ipfs config --json Gateway.PublicGateways '{ |
| 657 | "dnslink-enabled-on-fqdn.example.org": { |
| 658 | "NoDNSLink": false, |
| 659 | "UseSubdomains": false, |
| 660 | "Paths": ["/ipfs"] |
| 661 | }, |
| 662 | "only-dnslink-enabled-on-fqdn.example.org": { |
| 663 | "NoDNSLink": false, |
| 664 | "UseSubdomains": false, |
| 665 | "Paths": [] |
| 666 | }, |
| 667 | "dnslink-disabled-on-fqdn.example.com": { |
| 668 | "NoDNSLink": true, |
| 669 | "UseSubdomains": false, |
| 670 | "Paths": [] |
| 671 | } |
| 672 | }' || exit 1 |
| 673 | |
| 674 | # DNSLink test requires a daemon in online mode with precached /ipns/ mapping |
| 675 | DNSLINK_FQDN="dnslink-enabled-on-fqdn.example.org" |
| 676 | ONLY_DNSLINK_FQDN="only-dnslink-enabled-on-fqdn.example.org" |
| 677 | NO_DNSLINK_FQDN="dnslink-disabled-on-fqdn.example.com" |
| 678 | export IPFS_NS_MAP="$DNSLINK_FQDN:/ipfs/$CIDv1,$ONLY_DNSLINK_FQDN:/ipfs/$DIR_CID" |
| 679 | |
| 680 | # restart daemon to apply config changes |
| 681 | test_launch_ipfs_daemon |
| 682 | |
| 683 | # make sure test setup is valid (fail if CoreAPI is unable to resolve) |
| 684 | test_expect_success "spoofed DNSLink record resolves in cli" " |
| 685 | ipfs resolve /ipns/$DNSLINK_FQDN > result && |
| 686 | test_should_contain \"$CIDv1\" result && |
| 687 | ipfs cat /ipns/$DNSLINK_FQDN > result && |
| 688 | test_should_contain \"$CID_VAL\" result |
| 689 | " |
| 690 | |
| 691 | # DNSLink enabled |
| 692 | |
| 693 | test_hostname_gateway_response_should_contain \ |
| 694 | "request for http://{dnslink-fqdn}/ PublicGateway returns expected payload" \ |
| 695 | "$DNSLINK_FQDN" \ |
| 696 | "http://127.0.0.1:$GWAY_PORT/" \ |
| 697 | "$CID_VAL" |
| 698 | |
| 699 | test_hostname_gateway_response_should_contain \ |
| 700 | "request for {dnslink-fqdn}/ipfs/{cid} returns expected payload when /ipfs is on Paths whitelist" \ |
| 701 | "$DNSLINK_FQDN" \ |
| 702 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1" \ |
| 703 | "$CID_VAL" |
| 704 | |
| 705 | # Test for a fun edge case: DNSLink-only gateway without /ipfs/ namespace |
| 706 | # mounted, and with subdirectory named "ipfs" ¯\_(ツ)_/¯ |
| 707 | test_hostname_gateway_response_should_contain \ |
| 708 | "request for {dnslink-fqdn}/ipfs/file.txt returns data from content root when /ipfs in not on Paths whitelist" \ |
| 709 | "$ONLY_DNSLINK_FQDN" \ |
| 710 | "http://127.0.0.1:$GWAY_PORT/ipfs/file.txt" \ |
| 711 | "I am a txt file" |
| 712 | |
| 713 | test_hostname_gateway_response_should_contain \ |
| 714 | "request for {dnslink-fqdn}/ipns/{peerid} returns 404 when path is not whitelisted" \ |
| 715 | "$DNSLINK_FQDN" \ |
| 716 | "http://127.0.0.1:$GWAY_PORT/ipns/$RSA_IPNS_IDv0" \ |
| 717 | "404 Not Found" |
| 718 | |
| 719 | test_hostname_gateway_response_should_contain \ |
| 720 | "request for {dnslink-fqdn}/ipns/{peerid} returns 404 when path is not whitelisted" \ |
| 721 | "$DNSLINK_FQDN" \ |
| 722 | "http://127.0.0.1:$GWAY_PORT/ipns/$ED25519_IPNS_IDv0" \ |
| 723 | "404 Not Found" |
| 724 | |
| 725 | # DNSLink disabled |
| 726 | |
| 727 | test_hostname_gateway_response_should_contain \ |
| 728 | "request for http://{dnslink-fqdn}/ returns 404 when NoDNSLink=true" \ |
| 729 | "$NO_DNSLINK_FQDN" \ |
| 730 | "http://127.0.0.1:$GWAY_PORT/" \ |
| 731 | "404 Not Found" |
| 732 | |
| 733 | test_hostname_gateway_response_should_contain \ |
| 734 | "request for {dnslink-fqdn}/ipfs/{cid} returns 404 when path is not whitelisted" \ |
| 735 | "$NO_DNSLINK_FQDN" \ |
| 736 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv0" \ |
| 737 | "404 Not Found" |
| 738 | |
| 739 | |
| 740 | ## ============================================================================ |
| 741 | ## Test wildcard DNSLink (any hostname, with default config) |
| 742 | ## ============================================================================ |
| 743 | |
| 744 | test_kill_ipfs_daemon |
| 745 | |
| 746 | # enable wildcard DNSLink gateway (any value in Host header) |
| 747 | # and remove custom PublicGateways |
| 748 | ipfs config --json Gateway.NoDNSLink false && \ |
| 749 | ipfs config --json Gateway.PublicGateways '{}' || exit 1 |
| 750 | |
| 751 | # DNSLink test requires a daemon in online mode with precached /ipns/ mapping |
| 752 | DNSLINK_FQDN="wildcard-dnslink-not-in-config.example.com" |
| 753 | export IPFS_NS_MAP="$DNSLINK_FQDN:/ipfs/$CIDv1" |
| 754 | |
| 755 | # restart daemon to apply config changes |
| 756 | test_launch_ipfs_daemon |
| 757 | |
| 758 | # make sure test setup is valid (fail if CoreAPI is unable to resolve) |
| 759 | test_expect_success "spoofed DNSLink record resolves in cli" " |
| 760 | ipfs resolve /ipns/$DNSLINK_FQDN > result && |
| 761 | test_should_contain \"$CIDv1\" result && |
| 762 | ipfs cat /ipns/$DNSLINK_FQDN > result && |
| 763 | test_should_contain \"$CID_VAL\" result |
| 764 | " |
| 765 | |
| 766 | # gateway test |
| 767 | test_hostname_gateway_response_should_contain \ |
| 768 | "request for http://{dnslink-fqdn}/ (wildcard) returns expected payload" \ |
| 769 | "$DNSLINK_FQDN" \ |
| 770 | "http://127.0.0.1:$GWAY_PORT/" \ |
| 771 | "$CID_VAL" |
| 772 | |
| 773 | ## ============================================================================ |
| 774 | ## Test support for X-Forwarded-Host |
| 775 | ## ============================================================================ |
| 776 | |
| 777 | # set explicit subdomain gateway config for the hostname |
| 778 | ipfs config --json Gateway.PublicGateways '{ |
| 779 | "example.com": { |
| 780 | "UseSubdomains": true, |
| 781 | "Paths": ["/ipfs", "/ipns", "/api"] |
| 782 | } |
| 783 | }' || exit 1 |
| 784 | # restart daemon to apply config changes |
| 785 | test_kill_ipfs_daemon |
| 786 | test_launch_ipfs_daemon_without_network |
| 787 | |
| 788 | test_expect_success "request for http://fake.domain.com/ipfs/{CID} doesn't match the example.com gateway" " |
| 789 | curl -H \"Host: fake.domain.com\" -sD - \"http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1\" > response && |
| 790 | test_should_contain \"200 OK\" response |
| 791 | " |
| 792 | |
| 793 | test_expect_success "request for http://fake.domain.com/ipfs/{CID} with X-Forwarded-Host: example.com match the example.com gateway" " |
| 794 | curl -H \"Host: fake.domain.com\" -H \"X-Forwarded-Host: example.com\" -sD - \"http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1\" > response && |
| 795 | test_should_contain \"Location: http://$CIDv1.ipfs.example.com/\" response |
| 796 | " |
| 797 | |
| 798 | test_expect_success "request for http://fake.domain.com/ipfs/{CID} with X-Forwarded-Host: example.com and X-Forwarded-Proto: https match the example.com gateway, redirect with https" " |
| 799 | curl -H \"Host: fake.domain.com\" -H \"X-Forwarded-Host: example.com\" -H \"X-Forwarded-Proto: https\" -sD - \"http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1\" > response && |
| 800 | test_should_contain \"Location: https://$CIDv1.ipfs.example.com/\" response |
| 801 | " |
| 802 | |
| 803 | # Kubo specific end-to-end test |
| 804 | # (independent of gateway-conformance) |
| 805 | # test configuration being wired up correctly end-to-end |
| 806 | |
| 807 | ## ============================================================================ |
| 808 | ## Test support for wildcards in gateway config |
| 809 | ## ============================================================================ |
| 810 | |
| 811 | # set explicit subdomain gateway config for the hostnames |
| 812 | ipfs config --json Gateway.PublicGateways '{ |
| 813 | "*.example1.com": { |
| 814 | "UseSubdomains": true, |
| 815 | "Paths": ["/ipfs"] |
| 816 | }, |
| 817 | "*.*.example2.com": { |
| 818 | "UseSubdomains": true, |
| 819 | "Paths": ["/ipfs"] |
| 820 | }, |
| 821 | "foo.*.example3.com": { |
| 822 | "UseSubdomains": true, |
| 823 | "Paths": ["/ipfs"] |
| 824 | }, |
| 825 | "foo.bar-*-boo.example4.com": { |
| 826 | "UseSubdomains": true, |
| 827 | "Paths": ["/ipfs"] |
| 828 | } |
| 829 | }' || exit 1 |
| 830 | # restart daemon to apply config changes |
| 831 | test_kill_ipfs_daemon |
| 832 | test_launch_ipfs_daemon_without_network |
| 833 | |
| 834 | # *.example1.com |
| 835 | |
| 836 | test_hostname_gateway_response_should_contain \ |
| 837 | "request for foo.example1.com/ipfs/{CIDv1} produces redirect to {CIDv1}.ipfs.foo.example1.com" \ |
| 838 | "foo.example1.com" \ |
| 839 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1" \ |
| 840 | "Location: http://$CIDv1.ipfs.foo.example1.com/" |
| 841 | |
| 842 | test_hostname_gateway_response_should_contain \ |
| 843 | "request for {CID}.ipfs.foo.example1.com should return expected payload" \ |
| 844 | "${CIDv1}.ipfs.foo.example1.com" \ |
| 845 | "http://127.0.0.1:$GWAY_PORT/" \ |
| 846 | "$CID_VAL" |
| 847 | |
| 848 | # *.*.example2.com |
| 849 | |
| 850 | test_hostname_gateway_response_should_contain \ |
| 851 | "request for foo.bar.example2.com/ipfs/{CIDv1} produces redirect to {CIDv1}.ipfs.foo.bar.example2.com" \ |
| 852 | "foo.bar.example2.com" \ |
| 853 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1" \ |
| 854 | "Location: http://$CIDv1.ipfs.foo.bar.example2.com/" |
| 855 | |
| 856 | test_hostname_gateway_response_should_contain \ |
| 857 | "request for {CID}.ipfs.foo.bar.example2.com should return expected payload" \ |
| 858 | "${CIDv1}.ipfs.foo.bar.example2.com" \ |
| 859 | "http://127.0.0.1:$GWAY_PORT/" \ |
| 860 | "$CID_VAL" |
| 861 | |
| 862 | # foo.*.example3.com |
| 863 | |
| 864 | test_hostname_gateway_response_should_contain \ |
| 865 | "request for foo.bar.example3.com/ipfs/{CIDv1} produces redirect to {CIDv1}.ipfs.foo.bar.example3.com" \ |
| 866 | "foo.bar.example3.com" \ |
| 867 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1" \ |
| 868 | "Location: http://$CIDv1.ipfs.foo.bar.example3.com/" |
| 869 | |
| 870 | test_hostname_gateway_response_should_contain \ |
| 871 | "request for {CID}.ipfs.foo.bar.example3.com should return expected payload" \ |
| 872 | "${CIDv1}.ipfs.foo.bar.example3.com" \ |
| 873 | "http://127.0.0.1:$GWAY_PORT/" \ |
| 874 | "$CID_VAL" |
| 875 | |
| 876 | # foo.bar-*-boo.example4.com |
| 877 | |
| 878 | test_hostname_gateway_response_should_contain \ |
| 879 | "request for foo.bar-dev-boo.example4.com/ipfs/{CIDv1} produces redirect to {CIDv1}.ipfs.foo.bar-dev-boo.example4.com" \ |
| 880 | "foo.bar-dev-boo.example4.com" \ |
| 881 | "http://127.0.0.1:$GWAY_PORT/ipfs/$CIDv1" \ |
| 882 | "Location: http://$CIDv1.ipfs.foo.bar-dev-boo.example4.com/" |
| 883 | |
| 884 | test_hostname_gateway_response_should_contain \ |
| 885 | "request for {CID}.ipfs.foo.bar-dev-boo.example4.com should return expected payload" \ |
| 886 | "${CIDv1}.ipfs.foo.bar-dev-boo.example4.com" \ |
| 887 | "http://127.0.0.1:$GWAY_PORT/" \ |
| 888 | "$CID_VAL" |
| 889 | |
| 890 | ## ============================================================================ |
| 891 | ## Test support for overriding implicit defaults |
| 892 | ## ============================================================================ |
| 893 | |
| 894 | # disable subdomain gateway at localhost by removing implicit config |
| 895 | ipfs config --json Gateway.PublicGateways '{ |
| 896 | "localhost": null |
| 897 | }' || exit 1 |
| 898 | |
| 899 | # restart daemon to apply config changes |
| 900 | test_kill_ipfs_daemon |
| 901 | test_launch_ipfs_daemon_without_network |
| 902 | |
| 903 | test_localhost_gateway_response_should_contain \ |
| 904 | "request for localhost/ipfs/{CID} stays on path when subdomain gw is explicitly disabled" \ |
| 905 | "http://localhost:$GWAY_PORT/ipfs/$CIDv1" \ |
| 906 | "$CID_VAL" |
| 907 | |
| 908 | # ============================================================================= |
| 909 | # ensure we end with empty Gateway.PublicGateways |
| 910 | ipfs config --json Gateway.PublicGateways '{}' |
| 911 | test_kill_ipfs_daemon |
| 912 | |
| 913 | test_expect_success "clean up ipfs dir" ' |
| 914 | rm -rf "$IPFS_PATH" |
| 915 | ' |
| 916 | |
| 917 | test_done |
| 918 | |
| 919 | # end Kubo specific end-to-end test |