Web upload / download — Upload and download in the browser

Web upload / download allows end users to upload and download files directly through a web browser. External users without an installed agent can also transfer large files, while the web control handles chunked transfers, resume, and progress display.

There are three components.

ComponentRole
exabyter.js · exabyter.cssTransfer control embedded in the browser. Handles the file selection UI, chunked transfers, progress, and resume
upload.jsp / download.jspServer receive/send endpoints. This is where the actual storage path is configured
WEB-INF/lib/InnorixJAVA.jarTransfer library used by the endpoints

⚠️ Review the security requirements before deployment. The server endpoints accept values sent by the browser as-is. In particular, downloads append fileName to the file path, so without path validation, files outside the storage root may be exposed. Read the Required security measures section below first.

ℹ️ Code tabs — Because this configuration consists of a browser script + server endpoint, the examples are provided in two tabs: JavaScript (client) and JSP (server). The bundle generated by the builder also consists of these two file types.

Getting started

What the builder generates

Choose options in the Web upload / download tab of the builder and download them to generate a zip with the following structure. Extract it directly under webapps/ in Tomcat (or another servlet container) and it will run immediately.

text
exabyter-web-upload/
  upload.html            <- page built from the options you picked + exabyter.create({...})
  upload.jsp             <- receiving endpoint (set the storage path here)
  exabyter.js
  exabyter.css
  img/  font/            <- assets referenced by the css
  WEB-INF/lib/InnorixJAVA.jar
  README.txt

If you choose download mode, the same structure includes download.html · download.jsp.

After deployment, the main setting you need to change is the endpoint's storage path.

  • upload.jspdirectory (upload storage root), maxPostSize (maximum request body size)
  • download.jspfilePath (download source root)

Required security measures

The bundle generated by the builder is a minimal configuration for verifying functionality. Before exposing it to external users, you must apply the following four measures.

ItemIf left unchangedRequired action
Endpoint authenticationupload.jsp · download.jsp have no authentication, so anyone who knows the URL can call themCheck the session/token at the beginning of the page and return 401 on failure
Download path validationfileName becomes part of the file path directly, so ../ could read files outside the storage rootVerify that the canonical path remains inside the storage root. More securely, perform file ID → actual path mapping on the server and do not accept the path itself
Upload storage pathThe default is a data folder next to the JSP, which may be exposed through the webChange it to an absolute path outside the web-accessible area
CORSReflecting the request Origin directly allows arbitrary sites to call the endpointRestrict it to an allowlist of domains

The implementation examples below already include authentication checks, path validation, and domain restrictions. Change only the values to match your service.

Implementation

Upload

The control is rendered inside a single empty <div>.

html
<link rel="stylesheet" type="text/css" href="./exabyter.css">
<script src="./exabyter.js"></script>

<div id="fileControl"></div>

<div class="toolbar">
  <button onclick="control.openFileDialog()">Attach File</button>
  <button onclick="control.directoryDialog()">Attach Folder</button>
  <button onclick="control.upload()">Start Upload</button>
</div>
// upload.html - same shape as the bootstrap code the builder generates.
var control = exabyter.create({
    setElementID: '#fileControl',
    setViewType: 'ListView',
    transferMode: 'upload',
    setUploadURL: './upload.jsp',          // receiving endpoint
    setTransferStart: { upload: 'manual' }, // 'auto' = start as soon as files are selected

    // How files are attached - the builder's Method
    enableDropZone: true,                   // Drag & drop
    addFolder: true,                        // allow folder attachment (Files and folders)

    // File policy - the builder's File & storage rules
    allowType: ['pdf', 'docx', 'xlsx', 'png'],  // omit to allow every type
    maxFileCount: 50,
    maxFileSize: 1073741824,                // 1 GB (bytes)
    maxTotalSize: 10737418240,              // 10 GB (bytes)
    resumeType: 'numbering',                // duplicate name: overwrite | numbering | relay (resume)

    // Appearance
    showTransferWindow: true,
    showTransferStatusIcon: true,
    enableComplexFolders: false,            // hide the folder tree on the left (flat list)
    hideClientPath: true,
    transferWindowTitle: 'Exabyter',
    controlLang: 'ko',                      // control UI language
});

// Control is ready
control.on('loadComplete', function () {
    setStatus('Ready.', 'ready');
});

// All files attached - call upload() here to start automatically
control.on('afterAddFiles', function () {
    // control.upload();
});

control.on('uploadStart', function () {
    // Upload started
});

control.on('uploadProgress', function () {
    // Progress changed
});

control.on('uploadComplete', function () {
    setStatus('Upload complete.', 'done');
    // Call your service API on completion (the builder's Call API)
    fetch('/your/api', { method: 'POST', credentials: 'include' });
});

control.on('uploadError', function () {
    setStatus('Upload error - see the console for details.');
});

control.on('uploadCancel', function () {
    // Canceled by the user
});

Download

The key to downloads is passing the list of files to offer to the control. Items passed to setDownloadList() become the on-screen list, and only the items selected by the user are downloaded.

ℹ️ The JSP below contains the core logic for authentication checks, path validation, and integrity responses. The complete file, including byte-range calculations and streaming, is included in the bundle's download.jsp (downloaded through Get API Code). This code block alone does not constitute a complete download server.

// download.html
var control = exabyter.create({
    setElementID: '#fileControl',
    setViewType: 'ListView',
    transferMode: 'download',
    setTransferStart: { download: 'manual' },   // 'auto' = start as soon as the list is set

    downloadDuplicate: 'numbering',  // duplicate name: overwrite | numbering | resume
    downloadIntegrity: true,         // verify file integrity
    setVerification: 'enable',

    showTransferWindow: true,
    showTransferStatusIcon: true,
    enableComplexFolders: false,
    hideClientPath: true,
    transferWindowTitle: 'Exabyter',
    controlLang: 'ko',
});

control.on('loadComplete', function () {
    setStatus('Ready.', 'ready');
});

control.on('downloadStart', function () { /* transfer started */ });
control.on('downloadProgress', function () { /* progress changed */ });
control.on('downloadComplete', function () {
    setStatus('Download complete.', 'done');
});
control.on('downloadError', function () {
    setStatus('Download error - see the console for details.');
});
control.on('downloadCancel', function () { /* canceled by the user */ });

// Files to offer - usually mapped straight from your service API response.
control.setDownloadList([
    {
        downloadURL: './download.jsp?fileName=report_2026Q3.pdf',
        displayFileName: 'report_2026Q3.pdf',   // name shown to the user
        fileSize: 15728640,                     // bytes
        isFolder: false,
    },
    {
        downloadURL: './download.jsp?fileName=training_video.mp4',
        displayFileName: 'training_video.mp4',
        fileSize: 5368709120,
        isFolder: false,
    },
]);

// Wire up your buttons
// control.downloadSelectedFiles();  // selected items only
// control.download();               // everything

Server settings you must update

LocationValueDescription
upload.jspdirectoryUpload storage root. The default is the data folder next to the JSP, so change it to the actual storage path.
upload.jspmaxPostSizeMaximum request body size (bytes). This must be aligned with limits on the front-end proxy (nginx, etc.).
upload.jspCORSThe default code reflects the request Origin directly. In production, restrict it to allowed domains.
download.jspfilePathDownload source root.
CommonAuthentication · path validation · CORSBefore deployment, confirm again that the four Required security measures above have been applied.

To separate folders by user/transfer, configure the upload endpoint as follows.

java
// Per transfer
uploader.setDirectory(directory + "/" + uploader.getParameter("_transferId"));

// Per user (take the user id from the session)
String userId = (String) session.getAttribute("userId");
uploader.setDirectory(directory + "/" + userId);

// Per user and per transfer
uploader.setDirectory(directory + "/" + userId + "/" + uploader.getParameter("_transferId"));

Reference

Builder options ↔ generated code mapping

Upload tab

Builder itemOptionWhere it is applied
MethodDrag & dropenableDropZone: true
File select buttonenableDropZone: false + attach button
Connect to existing UIConnect control.upload() directly to the existing UI without a button
Start methodClick the upload buttonsetTransferStart: { upload: 'manual' }
Auto-start after selecting filesCall control.upload() in afterAddFiles
Selection targetSingle filemaxFileCount: 1
Files and foldersaddFolder: true + attach folder button
File typeImages / Documents / Videos / CustomallowType: [...]
Max file count1 / 10 / 50 / 100 / CustommaxFileCount
Max file size100MB / 1GB / 5GB / 10GB / CustommaxFileSize (bytes)
Max total size1GB / 5GB / 10GB / 50GB / CustommaxTotalSize (bytes)
Duplicate file nameOverwriteresumeType: 'overwrite'
Save with a new name / Don't overwriteresumeType: 'numbering'
Storage methodFixed folderUse directory in upload.jsp as-is
Per-user / Per-upload / Per-user & per-uploadBranch with uploader.setDirectory(...) in upload.jsp
Completion messageEnter messageStatus message in the uploadComplete handler
Call APIURL + POST/GETfetch(url, { method }) in uploadComplete
Developer event hooksSelected itemscontrol.on('uploadStart' | 'uploadProgress' | 'uploadComplete' | 'uploadError' | 'uploadCancel', …)

Download tab

Builder itemWhere it is applied
Files to offercontrol.setDownloadList([{ downloadURL, displayFileName, fileSize, isFolder }])
Start methodsetTransferStart: { download: 'manual' | 'auto' }
Duplicate namedownloadDuplicate: 'overwrite' | 'numbering' | 'resume'
IntegritydownloadIntegrity: true + setVerification: 'enable'
Event hookscontrol.on('downloadStart' | 'downloadProgress' | 'downloadComplete' | 'downloadError' | 'downloadCancel', …)

ℹ️ Items such as screen configuration (displayed file-list fields), file naming rules, access permissions, and availability period are determined by your service when building the list. Pass only the final list to the control. Files are transferred one by one exactly as listed.

Common errors

SymptomCause and solution
Control does not appearThe <div> referenced by setElementID does not exist when the script runs, or create() was called before exabyter.js loaded.
Upload fails immediately after startingThe setUploadURL path is incorrect or upload.jsp has not been deployed. Check for a 404 in the browser Network tab first.
CORS errorThe control sends OPTIONS before POST. The Access-Control-Allow-* headers must also be included in the OPTIONS response.
413 on large filesIncrease both maxPostSize and the request body size limit on the front-end proxy.
Files are saved to the wrong locationThe default directory is the data folder next to the JSP. Change it to an absolute path.
Korean filenames are corruptedCheck the JSP's pageEncoding="UTF-8" and the container's URI encoding setting (URIEncoding=UTF-8).
Extension restriction is not appliedallowType is a lowercase array without dots (['pdf','png']). Because this is client-side validation, validate it again on the server.
Download list is emptyConfirm that setDownloadList() is called after loadComplete and that each item has displayFileName.