
Fork des send-Moduls zur Behandlung von CVE-2017-20165
Send ist eine Bibliothek zum Streamen von Dateien aus dem Dateisystem als HTTP-Antwort. Sie unterstützt partielle Antworten (Ranges), Conditional-GET-Aushandlung (If-Match, If-Unmodified-Since, If-None-Match, If-Modified-Since), hohe Testabdeckung und granulare Ereignisse, die genutzt werden können, um in deiner Anwendung oder deinem Framework geeignete Maßnahmen zu ergreifen.
Dies ist ein Node.js-Modul, das über die
npm-Registry verfügbar ist. Die Installation erfolgt mit dem
npm install-Befehl:
$ npm install @fastify/send
@types/mime@3 muss verwendet werden, wenn TypeScript genutzt werden soll;
@types/mime@4 hat die mime-Typen entfernt.
$ npm install -D @types/mime@3
const send = require('@fastify/send')
Liefert statusCode, headers und stream für den angegebenen Pfad, um sie an eine
res zu senden. req ist die Node.js-HTTP-Anfrage und path ist ein urlencodierter Pfad,
der gesendet werden soll (urlencodiert, nicht der tatsächliche Dateisystempfad).
Aktiviert oder deaktiviert die Annahme von Bereichsanfragen (Range Requests), Standardwert ist true.
Wenn dies deaktiviert ist, wird Accept-Ranges nicht gesendet und der Inhalt
des Range-Anfrageheaders ignoriert.
Aktiviert oder deaktiviert das Setzen des Cache-Control-Antwortheaders, Standardwert ist
true. Wenn dies deaktiviert ist, werden die Optionen immutable und maxAge ignoriert.
Standardmäßig verwendet diese Bibliothek das mime-Modul, um den Content-Type
der Antwort basierend auf der Dateierweiterung der angeforderten Datei zu setzen.
Um diese Funktionalität zu deaktivieren, setze contentType auf false.
Der Content-Type-Header muss bei Deaktivierung manuell gesetzt werden.
Legt fest, wie mit „Dotfiles“ umgegangen wird, wenn sie auftreten. Eine Dotfile ist eine Datei
oder ein Verzeichnis, das mit einem Punkt („.“) beginnt. Beachte, dass diese Prüfung am
Pfad selbst erfolgt, ohne zu prüfen, ob der Pfad auf der Festplatte existiert.
Wenn root angegeben ist, werden nur die Dotfiles oberhalb des Roots geprüft
(d. h. der Root selbst kann sich innerhalb einer Dotfile befinden, wenn
auf „deny“ gesetzt).
'allow' Keine besondere Behandlung für Dotfiles.'deny' Sende einen 403 für jede Anfrage nach einer Dotfile.'ignore' Tue so, als ob die Dotfile nicht existiert, und sende 404.Der Standardwert ist ähnlich zu 'ignore', mit der Ausnahme, dass
dieser Standard die Dateien innerhalb eines Verzeichnisses, das mit einem Punkt beginnt,
nicht ignoriert, aus Gründen der Abwärtskompatibilität.
Byte-Offset, an dem der Stream endet, Standardwert ist die Länge der Datei
minus 1. Das Ende ist im Stream inklusiv, d. h. end: 3 schließt das
4. Byte im Stream ein.
Aktiviert oder deaktiviert die ETag-Erzeugung, Standardwert ist true.
Wenn eine bestimmte Datei nicht existiert, versuche, eine der angegebenen Erweiterungen
in der angegebenen Reihenfolge anzuhängen. Standardmäßig ist dies deaktiviert (auf false gesetzt). Ein
Beispielwert, der erweiterungslose HTML-Dateien ausliefert: ['html', 'htm'].
Dies wird übersprungen, wenn die angeforderte Datei bereits eine Erweiterung hat.
Aktiviert oder deaktiviert die immutable-Direktive im Cache-Control-Antwortheader,
Standardwert ist false. Wenn auf true gesetzt, sollte auch die Option maxAge
angegeben werden, um Caching zu ermöglichen. Die immutable-Direktive verhindert,
dass unterstützte Clients während der Gültigkeitsdauer der maxAge-Option bedingte Anfragen
stellen, um zu prüfen, ob sich die Datei geändert hat.
Standardmäßig unterstützt send „index.html“-Dateien. Um dies zu deaktivieren,
setze false, oder um ein neues Index zu übergeben, übergib einen String oder ein Array
in bevorzugter Reihenfolge.
Aktiviert oder deaktiviert den Last-Modified-Header, Standardwert ist true. Verwendet den
letzten Änderungszeitpunkt des Dateisystems.
Gib ein max-age in Millisekunden für HTTP-Caching an, Standardwert ist 0. Dies kann auch ein String sein, der vom ms-Modul akzeptiert wird.
Gib die maximale Antwortinhaltgröße an, Standardwert ist die gesamte Dateigröße.
Dies wird verwendet, wenn acceptRanges true ist.
Stellt Dateien relativ zu path bereit.
Byte-Offset, an dem der Stream beginnt, Standardwert ist 0. Der Start ist inklusiv,
d. h. start: 2 schließt das 3. Byte im Stream ein.
Wenn angegeben, setzt diese Option die maximale Anzahl von Bytes, die der interne Puffer hält, bevor das Lesen von der zugrunde liegenden Ressource pausiert wird. Wenn du diese Option weglässt (oder undefined übergibst), verwendet Node.js seinen eingebauten Standardwert für lesbare Binär-Streams.
Der mime-Export ist die globale Instanz des
mime-npm-Moduls.
Dies wird verwendet, um die MIME-Typen zu konfigurieren, die mit Dateierweiterungen verknüpft sind, sowie weitere Optionen zur Auflösung des MIME-Typs einer Datei (wie den Standardtyp, der für eine unbekannte Dateierweiterung verwendet werden soll).
Es führt kein internes Caching durch. Du solltest dafür einen Reverse-Proxy-Cache wie Varnish verwenden oder diese ausgefallenen Dinger namens CDNs. Wenn deine Anwendung klein genug ist, um von Single-Node-Speicher-Caching zu profitieren, ist sie klein genug, dass sie überhaupt kein Caching benötigt ;).
Um die debug()-Instrumentierungsausgabe zu aktivieren, exportiere NODE_DEBUG:
$ NODE_DEBUG=send node app
$ npm install
$ npm test
Dieses einfache Beispiel sendet eine bestimmte Datei an alle Anfragen.
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)
Dieses einfache Beispiel stellt einfach alle Dateien in einem
bestimmten Verzeichnis als oberste Ebene bereit. Zum Beispiel sendet eine Anfrage
GET /foo.txt den Inhalt von /www/public/foo.txt zurück.
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')
// Standardmäßig unbekannte Typen auf text/plain setzen
send.mime.default_type = 'text/plain'
// Einen benutzerdefinierten Typ hinzufügen
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)
Dies ist ein Beispiel für die Bereitstellung einer Verzeichnisstruktur mit einer benutzerdefinierten Funktion zum Rendern einer Auflistung eines Verzeichnisses.
const http = require('node:http')
const fs = require('node:fs')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
// Beliebige Dateien aus /www/example.com/public/* übertragen
// mit einem benutzerdefinierten Handler für die Verzeichnisauflistung
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') {
// Verzeichnisliste abrufen
const list = await readdir(metadata.path)
// einen Index für das Verzeichnis rendern
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) {
// beliebige Dateien aus
// /www/example.com/public/* übertragen
const { statusCode, headers, stream, type, metadata } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
switch (type) {
case 'directory': {
// deine benutzerdefinierte Verzeichnisbehandlungslogik:
res.writeHead(301, {
'Location': metadata.requestPath + '/'
})
res.end('Redirecting to ' + metadata.requestPath + '/')
break
}
case 'error': {
// deine benutzerdefinierte Fehlerbehandlungslogik:
res.writeHead(metadata.error.status ?? 500, {})
res.end(metadata.error.message)
break
}
default: {
// deine benutzerdefinierten Header
// alle Dateien zum Herunterladen bereitstellen
res.setHeader('Content-Disposition', 'attachment')
res.writeHead(statusCode, headers)
stream.pipe(res)
}
}
})
server.listen(3000)
Lizenziert unter MIT.