Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

fix: fix content-type detection by doing a fall-back based on the ext… #1482

Merged
merged 1 commit into from
Aug 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 26 additions & 20 deletions src/http/gateway/resources/gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ const Stream = require('readable-stream')
const { resolver } = require('ipfs-http-response')
const PathUtils = require('../utils/path')

function detectContentType (ref, chunk) {
let fileSignature

// try to guess the filetype based on the first bytes
// note that `file-type` doesn't support svgs, therefore we assume it's a svg if ref looks like it
if (!ref.endsWith('.svg')) {
fileSignature = fileType(chunk)
}

// if we were unable to, fallback to the `ref` which might contain the extension
const mimeType = mime.lookup(fileSignature ? fileSignature.ext : ref)

return mime.contentType(mimeType)
}

module.exports = {
checkCID: (request, reply) => {
if (!request.params.cid) {
Expand Down Expand Up @@ -97,7 +112,7 @@ module.exports = {
}

// response.continue()
let filetypeChecked = false
let contentTypeDetected = false
let stream2 = new Stream.PassThrough({ highWaterMark: 1 })
stream2.on('error', (err) => {
log.error('stream2 err: ', err)
Expand All @@ -108,29 +123,20 @@ module.exports = {
pull(
toPull.source(stream),
pull.through((chunk) => {
// Check file type. do this once.
if (chunk.length > 0 && !filetypeChecked) {
log('got first chunk')
let fileSignature = fileType(chunk)
log('file type: ', fileSignature)

filetypeChecked = true
const mimeType = mime.lookup(fileSignature
? fileSignature.ext
: null)
// Guess content-type (only once)
if (chunk.length > 0 && !contentTypeDetected) {
let contentType = detectContentType(ref, chunk)
contentTypeDetected = true

log('ref ', ref)
log('mime-type ', mimeType)

if (mimeType) {
log('writing mimeType')
log('mime-type ', contentType)

response
.header('Content-Type', mime.contentType(mimeType))
.send()
} else {
response.send()
if (contentType) {
log('writing content-type header')
response.header('Content-Type', contentType)
}

response.send()
}

stream2.write(chunk)
Expand Down
50 changes: 48 additions & 2 deletions test/gateway/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ const directoryContent = {
'nested-folder/hello.txt': loadFixture('test/gateway/test-folder/nested-folder/hello.txt'),
'nested-folder/ipfs.txt': loadFixture('test/gateway/test-folder/nested-folder/ipfs.txt'),
'nested-folder/nested.html': loadFixture('test/gateway/test-folder/nested-folder/nested.html'),
'cat-folder/cat.jpg': loadFixture('test/gateway/test-folder/cat-folder/cat.jpg')
'cat-folder/cat.jpg': loadFixture('test/gateway/test-folder/cat-folder/cat.jpg'),
'unsniffable-folder/hexagons-xml.svg': loadFixture('test/gateway/test-folder/unsniffable-folder/hexagons-xml.svg'),
'unsniffable-folder/hexagons.svg': loadFixture('test/gateway/test-folder/unsniffable-folder/hexagons.svg')
}

describe('HTTP Gateway', function () {
Expand Down Expand Up @@ -113,6 +115,22 @@ describe('HTTP Gateway', function () {
expect(file.hash).to.equal(expectedMultihash)
cb()
})
},
(cb) => {
const expectedMultihash = 'QmVZoGxDvKM9KExc8gaL4uTbhdNtWhzQR7ndrY7J1gWs3F'

let dir = [
content('unsniffable-folder/hexagons-xml.svg'),
content('unsniffable-folder/hexagons.svg')
]

http.api.node.files.add(dir, (err, res) => {
expect(err).to.not.exist()
const file = res[res.length - 2]
expect(file.path).to.equal('test-folder/unsniffable-folder')
expect(file.hash).to.equal(expectedMultihash)
cb()
})
}
], done)
})
Expand Down Expand Up @@ -166,7 +184,7 @@ describe('HTTP Gateway', function () {
})
})

it('load a non text file', (done) => {
it('load a jpg file', (done) => {
let kitty = 'QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ/cat.jpg'

gateway.inject({
Expand All @@ -184,6 +202,34 @@ describe('HTTP Gateway', function () {
})
})

it('load a svg file (unsniffable)', (done) => {
let hexagons = 'QmVZoGxDvKM9KExc8gaL4uTbhdNtWhzQR7ndrY7J1gWs3F/hexagons.svg'

gateway.inject({
method: 'GET',
url: '/ipfs/' + hexagons
}, (res) => {
expect(res.statusCode).to.equal(200)
expect(res.headers['content-type']).to.equal('image/svg+xml')

done()
})
})

it('load a svg file with xml leading declaration (unsniffable)', (done) => {
let hexagons = 'QmVZoGxDvKM9KExc8gaL4uTbhdNtWhzQR7ndrY7J1gWs3F/hexagons-xml.svg'

gateway.inject({
method: 'GET',
url: '/ipfs/' + hexagons
}, (res) => {
expect(res.statusCode).to.equal(200)
expect(res.headers['content-type']).to.equal('image/svg+xml')

done()
})
})

it('load a directory', (done) => {
let dir = 'QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ/'

Expand Down
56 changes: 56 additions & 0 deletions test/gateway/test-folder/unsniffable-folder/hexagons-xml.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 55 additions & 0 deletions test/gateway/test-folder/unsniffable-folder/hexagons.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.