All Projects → Buzut → huge-uploader-nodejs

Buzut / huge-uploader-nodejs

Licence: BSD-3-Clause license
Node.js module to handle chunked file uploads sent by huge-uploader

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to huge-uploader-nodejs

Rhino3dm
Libraries based on OpenNURBS with a RhinoCommon style
Stars: ✭ 232 (+728.57%)
Mutual labels:  javascript-library
Webpack Library Example
An example of how to author libraries using webpack.
Stars: ✭ 251 (+796.43%)
Mutual labels:  javascript-library
previewer
A super light-weight JavaScript image previewer [not actively maintained]
Stars: ✭ 24 (-14.29%)
Mutual labels:  javascript-library
React
MOVED TO https://github.com/myitcv/x/blob/master/react/_doc/README.md
Stars: ✭ 234 (+735.71%)
Mutual labels:  javascript-library
Jfa Pwa Toolkit
⚡️ PWA Features to Any Website (very Fast & Easy)
Stars: ✭ 245 (+775%)
Mutual labels:  javascript-library
SABRE.js
Substation Alpha suBtitles REnderer -- A Gpu Accelerated Javascript Advanced SubStation (ASS) Alpha Subtitles Renderer. Renders .ass and .ssa files.
Stars: ✭ 58 (+107.14%)
Mutual labels:  javascript-library
Inquirer.js
A collection of common interactive command line user interfaces.
Stars: ✭ 15,378 (+54821.43%)
Mutual labels:  javascript-library
nexus-bridge
Nexus Bridge is a JS library that works with Siebel Presentation Model and allows building Siebel UI using the modern JS frameworks.
Stars: ✭ 21 (-25%)
Mutual labels:  javascript-library
Easter Egg Collection
🐰 A funny library for tricking your colleagues.
Stars: ✭ 249 (+789.29%)
Mutual labels:  javascript-library
FixLanguageTypeJs
Tiny Library for fix problem of language selection in type text.
Stars: ✭ 15 (-46.43%)
Mutual labels:  javascript-library
Spectra
A Javascript color library. Quickly manipulate and convert colors.
Stars: ✭ 235 (+739.29%)
Mutual labels:  javascript-library
Ac Colors
ac-colors is a reactive JavaScript color library that can freely convert between RGB, HSL, HEX, XYZ, LAB, LCHab, LUV, and LCHuv, as well as handle random color generation and contrast ratio calculation.
Stars: ✭ 243 (+767.86%)
Mutual labels:  javascript-library
CopyPasteJS
This a small JS library to execute clipboard functions in a fast and easy way.
Stars: ✭ 20 (-28.57%)
Mutual labels:  javascript-library
Collectable
High-performance immutable data structures for modern JavaScript and TypeScript applications. Functional interfaces, deep/composite operations API, mixed mutability API, TypeScript definitions, ES2015 module exports.
Stars: ✭ 233 (+732.14%)
Mutual labels:  javascript-library
fyu
Do your users take your website for granted? Do want to make them using your website living hell? Look no further, F.Y.U. is here!
Stars: ✭ 53 (+89.29%)
Mutual labels:  javascript-library
Bbo
bbo is a utility library of zero dependencies for javascript. 🍖🌭🍔
Stars: ✭ 227 (+710.71%)
Mutual labels:  javascript-library
Inferno
🔥 An extremely fast, React-like JavaScript library for building modern user interfaces
Stars: ✭ 15,206 (+54207.14%)
Mutual labels:  javascript-library
Modern.JS
모던 자바스크립트 라이브러리/프레임워크 × KIPFA(한국인터넷전문가협회)
Stars: ✭ 16 (-42.86%)
Mutual labels:  javascript-library
wp-original-media-path
Change the location for the uploads folder for WordPress
Stars: ✭ 22 (-21.43%)
Mutual labels:  uploads
vanillaview
Easy to use views with vanilla JS semantics
Stars: ✭ 12 (-57.14%)
Mutual labels:  javascript-library

huge uploader nodejs

huge-uploader-nodejs is a Node.js promise-based module made to receive chunked & resumable file uploads. It's made to work with its frontend counterpart huge-uploader.

From huge-uploader:

HTTP and especially HTTP servers have limits and were not designed to transfer large files. In addition, network connexion can be unreliable. No one wants an upload to fail after hours… Sometimes we even need to pause the upload, and HTTP doesn't allow that.

The best way to circumvent these issues is to chunk the file and send it in small pieces. If a chunk fails, no worries, it's small and fast to re-send it. Wanna pause? Ok, just start where you left off when ready.

The frontend module chunks and sends, this backend module receives and assembles all the pieces back together at the end of the process.

Installation & usage

npm install huge-uploader-nodejs --save

As an exemple, I'll give something in pure Node.js, without any framework. But it is obviously compatible with any framework out there.

const http = require('http');
const uploader = require('huge-uploader-nodejs');

// you must specify a temp upload dir and a max filesize for the chunks
const tmpDir = './tmp';
const maxFileSize = 10;

http.createServer((req, res) => {
    if (req.url === '/upload' && req.method === 'POST') {
        // we feed the function with node's request object (here req),
        // the temp directory path and the max size for the chunks
        uploader(req, tmpDir, maxFileSize, maxChunkSize)
        .then((assembleChunks) => {
            // chunk written to disk
            res.writeHead(204, 'No Content');
            res.end();

            // on last chunk, assembleChunks function is returned
            // the response is already sent to the browser because it can take some time if the file is huge
            if (assembleChunks) {
                // so you call the promise, it assembles all the pieces together and cleans the temporary files
                assembleChunks()
                // when it's done, it returns an object with the path to the file and additional post parameters if any
                .then(data => console.log(data)) // { filePath: 'tmp/1528932277257', postParams: { email: '[email protected]', name: 'Mr Smith' } }
                // errors if any are triggered by the file system (disk is full…)
                .catch(err => console.log(err));
            }
        })
        .catch((err) => {
            if (err.message === 'Missing header(s)') {
                res.writeHead(400, 'Bad Request', { 'Content-Type': 'text/plain' });
                res.end('Missing uploader-* header');
                return;
            }

            if (err.message === 'Missing Content-Type') {
                res.writeHead(400, 'Bad Request', { 'Content-Type': 'text/plain' });
                res.end('Missing Content-Type');
                return;
            }

            if (err.message.includes('Unsupported content type')) {
                res.writeHead(400, 'Bad Request', { 'Content-Type': 'text/plain' });
                res.end('Unsupported content type');
                return;
            }

            if (err.message === 'Chunk is out of range') {
                res.writeHead(400, 'Bad Request', { 'Content-Type': 'text/plain' });
                res.end('Chunk number must be between 0 and total chunks - 1 (0 indexed)');
                return;
            }

            if (err.message === 'File is above size limit') {
                res.writeHead(413, 'Payload Too Large', { 'Content-Type': 'text/plain' });
                res.end(`File is too large. Max fileSize is: ${maxFileSize}MB`);
                return;
            }

            if (err.message === 'Chunk is above size limit') {
                res.writeHead(413, 'Payload Too Large', { 'Content-Type': 'text/plain' });
                res.end(`Chunk is too large. Max chunkSize is: ${maxChunkSize}MB`);
                return;
            }

			// this error is triggered if a chunk with uploader-chunk-number header != 0
            // is sent and there is no corresponding temp dir.
            // It means that the upload dir has been deleted in the meantime.
            // Although uploads should be resumable, you can't keep partial uploads for days on your server
            if (err && err.message === 'Upload has expired') {
                res.writeHead(410, 'Gone', { 'Content-Type': 'text/plain' });
                res.end(err.message);
                return;
            }

            // other FS errors
            res.writeHead(500, 'Internal Server Error'); // potentially saturated disk
            res.end();
        });
    }

    // unknown route
    else {
        res.writeHead(404, 'Resource Not Found', { 'Content-Type': 'text/plain' });
        res.end('Resource Not Found');
    }
})
.listen(8888, () => {
    console.log('Listening for requests');
});

Also, if the uploader is not on the same domain, don't forget to set a CORS policy. Either directly on node or on the reverse proxy. Here's an exemple for Node:

res.setHeader('Access-Control-Allow-Origin', 'https://my-super-domain.com');

if (req.url === '/upload' && req.method === 'OPTIONS') {
    res.setHeader('Access-Control-Allow-Methods', 'POST,OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'uploader-chunk-number,uploader-chunks-total,uploader-file-id');
    res.setHeader('Access-Control-Max-Age', '86400'); // 24hrs
    res.writeHead(204, 'No Content');
    res.end();
    return;
 }

Options

They aren't many options (all are required). As shown in the example, you pass the function:

  • the request object,
  • a directory to write to { String },
  • the maximum total file size for the upload { Number },
  • the maximum chunk size { Number }.

Be warned that total file size is computed by multiplying maxChunkSize by uploader-chunks-total header. So if the client is splitting files in chunks smaller than maxChunkSize, leading to a situation where uploader-chunks-total > maxFileSize / maxChunkSize, the upload will be refused although it might be smaller than maxFileSize.

Garbage collection

As said in the exemple, the module takes care of cleaning the successful uploads. But if an upload is paused and never resumed, its files are going to stay forever. So you should create a script called via a crontab that will erased directory older than the time you're willing to keep them.

Example bash script:

#!/bin/bash

find /var/www/tmp -type d -mtime +1 -delete

How to setup with the frontend

This module is made to work with huge-uploader frontend module. In case you would like to develop your own frontend, this module needs three specific headers to work:

  • uploader-file-id a unique file id that's used to create temp upload directory for this upload,
  • uploader-chunks-total the total numbers of chunk that will be sent,
  • uploader-chunk-number the current chunk number (0 based index, so last chunk is uploader-chunks-total - 1).

Any other header will be ignored. Also, you can send POST parameters. Parameters send with the last chunk only will be processed.

Contributing

There's sure room for improvement, so feel free to hack around and submit PRs! Please just follow the style of the existing code, which is Airbnb's style with minor modifications.

To maintain things clear and visual, please follow the git commit template.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].