ipfs_proxy.js 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. const { createProxyMiddleware } = require('http-proxy-middleware')
  2. const debug = require('debug')('joystream:ipfs-proxy')
  3. const mime = require('mime-types')
  4. /*
  5. For this proxying to work correctly, ensure IPFS HTTP Gateway is configured as a path gateway:
  6. This can be done manually with the following command:
  7. $ ipfs config --json Gateway.PublicGateways '{"localhost": null }'
  8. The implicit default config is below which is not what we want!
  9. $ ipfs config --json Gateway.PublicGateways '{
  10. "localhost": {
  11. "Paths": ["/ipfs", "/ipns"],
  12. "UseSubdomains": true
  13. }
  14. }'
  15. https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#gateway
  16. */
  17. const pathFilter = function (path, req) {
  18. // we get the full path here so it needs to match the path where
  19. // it is used by the openapi initializer
  20. return path.match('^/asset/v0') && (req.method === 'GET' || req.method === 'HEAD')
  21. }
  22. const createPathRewriter = () => {
  23. return async (_path, req) => {
  24. const hash = req.params.ipfs_content_id
  25. return `/ipfs/${hash}`
  26. }
  27. }
  28. const createProxy = (ipfsHttpGatewayUrl) => {
  29. const pathRewrite = createPathRewriter()
  30. return createProxyMiddleware(pathFilter, {
  31. // Default path to local IPFS HTTP GATEWAY
  32. target: ipfsHttpGatewayUrl || 'http://localhost:8080/',
  33. pathRewrite,
  34. onProxyRes: function (proxRes, req, res) {
  35. /*
  36. Make sure the reverse proxy used infront of colosss (nginx/caddy) Does not duplicate
  37. these headers to prevent some browsers getting confused especially
  38. with duplicate access-control-allow-origin headers!
  39. 'accept-ranges': 'bytes',
  40. 'access-control-allow-headers': 'Content-Type, Range, User-Agent, X-Requested-With',
  41. 'access-control-allow-methods': 'GET',
  42. 'access-control-allow-origin': '*',
  43. 'access-control-expose-headers': 'Content-Range, X-Chunked-Output, X-Stream-Output',
  44. */
  45. if (proxRes.statusCode === 301) {
  46. // capture redirect when IPFS HTTP Gateway is configured with 'UseDomains':true
  47. // and treat it as an error.
  48. console.error('IPFS HTTP Gateway is configured for "UseSubdomains". Killing stream')
  49. res.status(500).end()
  50. proxRes.destroy()
  51. } else {
  52. // Handle downloading as attachment /asset/v0/:id?download
  53. if (req.query.download) {
  54. const contentId = req.params.id
  55. const contentType = proxRes.headers['content-type']
  56. const ext = mime.extension(contentType) || 'bin'
  57. const fileName = `${contentId}.${ext}`
  58. proxRes.headers['Content-Disposition'] = `attachment; filename=${fileName}`
  59. }
  60. }
  61. },
  62. })
  63. }
  64. module.exports = {
  65. createProxy,
  66. }