
CVE-2017-20165를 처리하기 위한 send 모듈의 포크
Send는 파일 시스템에서 파일을 HTTP 응답으로 스트리밍하기 위한 라이브러리로, 부분 응답(Ranges), 조건부 GET 협상(If-Match, If-Unmodified-Since, If-None-Match, If-Modified-Since), 높은 테스트 커버리지, 그리고 애플리케이션이나 프레임워크에서 적절한 조치를 취하는 데 활용할 수 있는 세분화된 이벤트를 지원합니다.
이 모듈은 npm 레지스트리를 통해 제공되는 Node.js 모듈입니다. 설치 방법은 npm install 명령어를 사용하여 수행합니다:
$ npm install @fastify/send
TypeScript를 사용하려면 @types/mime@3을(를) 사용해야 합니다. @types/mime@4에는 mime 타입이 제거되었습니다.
$ npm install -D @types/mime@3
const send = require('@fastify/send')
지정된 path에 대해 res로 보낼 statusCode, headers 및 stream을 제공합니다. req는 Node.js HTTP 요청이고 path는 보낼 urlencoded 경로입니다(실제 파일 시스템 경로가 아닌 urlencoded 경로).
범위 요청 수락을 활성화 또는 비활성화합니다. 기본값은 true입니다.
이 옵션을 비활성화하면 Accept-Ranges를 보내지 않으며 Range 요청 헤더의 내용을 무시합니다.
Cache-Control 응답 헤더 설정을 활성화 또는 비활성화합니다. 기본값은 true입니다. 비활성화하면 immutable 및 maxAge 옵션을 무시합니다.
기본적으로 이 라이브러리는 mime 모듈을 사용하여 요청된 파일의 파일 확장자를 기반으로 응답의 Content-Type을 설정합니다.
이 기능을 비활성화하려면 contentType을 false로 설정하세요.
비활성화된 경우 Content-Type 헤더를 수동으로 설정해야 합니다.
점으로 시작하는 파일(".")을 만났을 때 "dotfile"을 어떻게 처리할지 설정합니다. 이 검사는 디스크에 경로가 존재하는지 확인하지 않고 경로 자체에서 수행됩니다. root가 지정된 경우 root 위의 dotfile만 검사됩니다(즉, "deny"로 설정된 경우 root 자체가 dotfile 안에 있을 수 있습니다).
'allow' dotfile에 대한 특별한 처리가 없습니다.'deny' dotfile에 대한 모든 요청에 403을 보냅니다.'ignore' dotfile이 존재하지 않는 것처럼 처리하고 404를 반환합니다.기본값은 'ignore'와 _유사_하지만, 이 기본값은 이전 버전과의 호환성을 위해 점으로 시작하는 디렉토리 내의 파일은 무시하지 않는다는 예외가 있습니다.
스트림이 끝나는 바이트 오프셋입니다. 기본값은 파일 길이에서 1을 뺀 값입니다. end는 스트림에 포함되므로 end: 3은 스트림에 4번째 바이트를 포함합니다.
etag 생성을 활성화 또는 비활성화합니다. 기본값은 true입니다.
주어진 파일이 존재하지 않으면 주어진 확장자 중 하나를 주어진 순서대로 추가해 봅니다. 기본적으로 비활성화되어 있습니다(false로 설정). 확장자가 없는 HTML 파일을 제공하는 예제 값: ['html', 'htm']. 요청된 파일에 이미 확장자가 있으면 이 기능은 건너뜁니다.
Cache-Control 응답 헤더에서 immutable 지시문을 활성화 또는 비활성화합니다. 기본값은 false입니다. true로 설정하면 캐싱을 활성화하기 위해 maxAge 옵션도 지정해야 합니다. immutable 지시문은 지원되는 클라이언트가 maxAge 옵션의 수명 동안 조건부 요청을 통해 파일이 변경되었는지 확인하는 것을 방지합니다.
기본적으로 send는 "index.html" 파일을 지원합니다. 비활성화하려면 false로 설정하거나 새 인덱스를 전달하려면 선호 순서에 따라 문자열이나 배열을 전달하세요.
Last-Modified 헤더를 활성화 또는 비활성화합니다. 기본값은 true입니다. 파일 시스템의 마지막 수정 값을 사용합니다.
HTTP 캐싱을 위한 max-age(밀리초)를 제공합니다. 기본값은 0입니다. 이 값은 ms 모듈이 허용하는 문자열일 수도 있습니다.
최대 응답 콘텐츠 크기를 지정합니다. 기본값은 전체 파일 크기입니다. 이 값은 acceptRanges가 true일 때 사용됩니다.
path를 기준으로 파일을 제공합니다.
스트림이 시작되는 바이트 오프셋입니다. 기본값은 0입니다. start는 포함되므로 start: 2는 스트림에 3번째 바이트를 포함합니다.
이 옵션을 제공하면 내부 버퍼가 기본 리소스 읽기를 일시 중지하기 전에 보유할 최대 바이트 수를 설정합니다. 이 옵션을 생략하거나(또는 undefined를 전달하면) Node.js는 읽기 가능한 이진 스트림에 대한 내장 기본값을 사용합니다.
mime 내보내기는 mime npm 모듈의 전역 인스턴스입니다.
이것은 파일 확장자와 연결된 MIME 유형을 구성하고 파일의 MIME 유형을 해석하는 방법에 대한 다른 옵션(예: 알 수 없는 파일 확장자에 사용할 기본 유형)을 구성하는 데 사용됩니다.
내부 캐싱을 수행하지 않습니다. 이를 위해 Varnish와 같은 리버스 프록시 캐시나 CDN이라고 하는 멋진 것들을 사용해야 합니다. 애플리케이션이 단일 노드 메모리 캐싱의 이점을 누릴 만큼 작다면 캐싱이 전혀 필요하지 않을 만큼 작은 것입니다 ;).
debug() 계측 출력을 활성화하려면 __NODE_DEBUG__를 내보내십시오:
$ NODE_DEBUG=send node app
$ npm install
$ npm test
이 간단한 예제는 모든 요청에 특정 파일을 보냅니다.
const http = require('node:http')
const send = require('send')
const server = http.createServer(async function onRequest (req, res) {
const { statusCode, headers, stream } = await send(req, '/path/to/index.html')
res.writeHead(statusCode, headers)
stream.pipe(res)
})
server.listen(3000)
이 간단한 예제는 주어진 디렉토리의 모든 파일을 최상위 수준으로 제공합니다. 예를 들어 GET /foo.txt 요청은 /www/public/foo.txt를 다시 보냅니다.
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
const server = http.createServer(async function onRequest (req, res) {
const { statusCode, headers, stream } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
res.writeHead(statusCode, headers)
stream.pipe(res)
})
server.listen(3000)
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
// Default unknown types to text/plain
send.mime.default_type = 'text/plain'
// Add a custom type
send.mime.define({
'application/x-my-type': ['x-mt', 'x-mtt']
})
const server = http.createServer(function onRequest (req, res) {
const { statusCode, headers, stream } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
res.writeHead(statusCode, headers)
stream.pipe(res)
})
server.listen(3000)
이것은 디렉토리 목록을 렌더링하는 사용자 정의 함수로 디렉토리 구조를 제공하는 예제입니다.
const http = require('node:http')
const fs = require('node:fs')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
// Transfer arbitrary files from within /www/example.com/public/*
// with a custom handler for directory listing
const server = http.createServer(async function onRequest (req, res) {
const { statusCode, headers, stream, type, metadata } = await send(req, parseUrl(req).pathname, { index: false, root: '/www/public' })
if(type === 'directory') {
// get directory list
const list = await readdir(metadata.path)
// render an index for the directory
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' })
res.end(list.join('\n') + '\n')
} else {
res.writeHead(statusCode, headers)
stream.pipe(res)
}
})
server.listen(3000)
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
const server = http.createServer(async function onRequest (req, res) {
// transfer arbitrary files from within
// /www/example.com/public/*
const { statusCode, headers, stream, type, metadata } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
switch (type) {
case 'directory': {
// your custom directory handling logic:
res.writeHead(301, {
'Location': metadata.requestPath + '/'
})
res.end('Redirecting to ' + metadata.requestPath + '/')
break
}
case 'error': {
// your custom error-handling logic:
res.writeHead(metadata.error.status ?? 500, {})
res.end(metadata.error.message)
break
}
default: {
// your custom headers
// serve all files for download
res.setHeader('Content-Disposition', 'attachment')
res.writeHead(statusCode, headers)
stream.pipe(res)
}
}
})
server.listen(3000)
MIT 라이선스에 따라 사용이 허가됩니다.