# MCWebAccess

WebAccess is for manually started file sharing on a local network. It does not start automatically.
OpenSSL remains the TLS dependency; this update does not enable HTTPS.

## Sharing a file or receiving files

1. Add files or folders to the WebAccess workspace.
2. While sharing is stopped, open **Session settings** to choose a port and optionally a password.
   A blank password keeps access password-free. With a password, sign in with username **share**.
   The port and password selected here apply to this session only; the password is not saved to a layout or configuration file.
3. Use **Properties** on a shared item to allow downloads, uploads, or both. A receive-only folder allows uploads without listing files.
   Share permissions are stored when the layout is saved. Older layouts keep their existing read/write defaults.
4. Click **Start sharing**, then open **Sharing link** on the toolbar. Choose a network address and use **Copy URL**,
   **Open in browser**, or scan the QR code from a phone on the same network. Local-only addresses are clearly marked.
   The URL and QR code contain no password; if one is set, the browser asks for username **share** and the session password.
5. Click **Stop sharing** when finished.

The optional password uses HTTP Basic authentication; it controls access but does not encrypt HTTP traffic.
HTTPS configuration is separate and is not exposed by these session settings.

## Transfers and sharing changes

- The browser UI works offline and uses assets from the extension's own directory.
- Uploads are acknowledged one chunk at a time, limiting queued browser data on slow connections.
- Downloads use native Windows Unicode paths and stream file data without loading the entire file into memory.
- Files are written to temporary names and appear under their requested names only after explicit completion.
- Cancellation, disconnection, share revocation and shutdown remove incomplete temporary files.
- Existing destination files are never replaced. Upload filenames cannot contain paths, alternate data streams or Windows device names.
- Share changes refresh the server snapshot while preserving cached URLs and active uploads for unchanged shares.
  Removed or changed destinations and denied permissions revoke access. Downloads already accepted may finish;
  stopping sharing stops the listener and its connections.
- Filesystem links discovered inside a shared folder are not followed. A folder link may still be chosen as an explicit share.
- Browser requests from other origins are rejected, including WebSocket handshakes.

## Folder listing responsiveness

Directory scans, page formatting, file metadata lookup for downloads and streamed response writes run outside the
shared model lock. Cache reconciliation uses a name lookup, avoiding repeated full searches through large folders.
Upload cleanup on disconnect and shutdown also releases the model lock before closing or deleting temporary files.
The server uses three request workers in addition to Crow's acceptor thread.

A folder has only one scan in flight. Concurrent requests can use its previous listing with a refresh notice,
leaving workers available for other requests. If the folder has no previous listing yet, an overlapping request
gets a temporary busy response with `Retry-After: 1` instead of an empty listing. Enumeration failures keep the
previous cache intact. Scan results are discarded if the destination is removed or replaced before publication;
current access permissions are applied when the response snapshot is created.

## Refreshing the browser file list

Use **Refresh** beside the page heading to update the current folder without reloading the page.
The upload queue, active uploads and completed/failed results stay intact. A failed refresh keeps the existing
listing visible and shows a retry message. Root listings and nested folders use their current URL.
The listing also refreshes after an upload batch saves at least one file, including a batch with other failures
or cancellation. Concurrent refreshes run in order so a completion during an earlier scan is not missed.
Search text and sort order survive both manual and automatic refreshes. Refresh requests time out after 15 seconds,
restore the button on failure, and coalesce repeated triggers into at most one pending follow-up.

## Finding files and viewing text

Filter the current folder by filename with **Search**. Sort by name, size or modified date using the column
headings or the **Sort** menu (also available on phones). Folders stay first; names use natural ordering,
and sizes sort by exact byte counts. Readable sizes include an exact-byte tooltip; the counter shows visible/total items.
The filter applies only to the currently listed folder. Filtering reuses the current row order rather than sorting and moving every row again.

**View text** beside a `.txt` file opens an inline plain-text preview in a new tab. Downloads remain available
through the filename. Previews support UTF-8, BOM-marked UTF-16 and the host's Windows ANSI code page as a fallback.
Only the first 1 MiB is read for display, with a notice for larger files. Binary data with NUL characters is rejected.
Preview content is served as `text/plain` with `nosniff`, a sandbox policy and the same read/password checks as downloads.
File reads validate the opened object against the opened shared root and keep both handles alive. Downloads stream
from that same validated handle, without reopening a pathname between validation and sending. A stale cached file
cannot escape the share through a replaced parent junction. Case-sensitive sibling directories remain distinct.
Responses prevent framing and do not send referrers.

## Active transfers

Open **Active transfers** on the extension toolbar while sharing is running. The desktop window shows each active
upload/download's client IP, direction, filename, bytes and average speed. Select a row and choose **Cancel selected**
to stop that transfer. Upload cancellation removes the incomplete temporary file; a later browser chunk receives an error.
Plain HTTP writes use bounded nonblocking retries: cancellation and shutdown are checked while a receiver stalls,
and a write with no progress for 30 seconds is aborted. Download progress measures bytes sent by the server, not remote receipt or saving.
The list refreshes twice per second, preserves the selected transfer by identity, and removes finished transfers.
Cancelling an upload skips unrelated connection locks. The upload worker also checks the cancellation state before
writing data or finalizing, including requests racing with cancellation.

## Log view

Folder requests and transfer events have a `[client IP]` prefix taken from the actual connection.
Folder listings use one entry with the virtual path and item count. Downloads log their start and size, or the
HTTP failure status; a start entry is not a confirmation that the remote browser received the entire file.
Uploads log start, successful finalization, rejection/failure, connection interruption and sharing shutdown, with
filenames and received/expected byte counts. The log avoids per-chunk messages, duplicate failure messages,
raw upload metadata, passwords and Authorization headers. Request details are kept on a single log line.

## Browser upload queue

Choose multiple files or drag files onto the upload area, then select **Start uploads**. You can add more files
before starting. The list shows each file's progress and outcome, plus overall received data, average upload speed
and estimated remaining time. Speed and time are estimated from acknowledged bytes, including connection time.

Uploads run sequentially, with only one chunk awaiting acknowledgement at a time. The next file starts only after
the previous upload has been finalized. A rejected file is marked failed and the queue continues; a lost connection
stops the queue. **Cancel uploads** stops the current transfer and leaves the remaining files waiting.
**Retry unfinished** retries failed, cancelled and waiting files while keeping completed uploads. Existing server
files are never replaced. **Clear list** clears the browser list; files already uploaded remain on the server.
Each row also has **Remove**, plus **Retry** for an individual failed/cancelled file. Queued files can be removed
while another file uploads; the active row cannot be removed. Individual retry leaves other queued files waiting.
Duplicate filenames are detected without case sensitivity when adding files, with a warning instead of a second row.
Dropped folders are rejected; directory trees are not uploaded.
Progress reaches 100% only after the server confirms the save. If the connection is lost or cancellation occurs
while waiting for this confirmation, the file may already exist on the server; the file's status asks you to check
the shared folder before retrying. Retrying never overwrites an existing file.

## Build

Dependencies are supplied by vcpkg: Crow, Asio, OpenSSL and fmt. Run `vcpkg integrate install` on a new developer machine,
then reopen Visual Studio and build MCWebAccess. The static triplet must match the target platform and static CRT.
`PostBuild.bat` deploys the DLL, page template and uploader script together.

The pinned vcpkg registry supplies Asio 1.38.2, OpenSSL 3.6.5#2 and fmt 12.2.0#1.

The manifest configuration selects the project-local `vcpkg-overlays/crow` port (Crow 1.3.5).
Its patches add a Windows wide-path streaming overload, 64-bit file metadata, streamed progress/cancellation hooks, validated file-handle readers and interruptible plain HTTP writes. Reinstall the manifest dependencies
for each target triplet after updating the overlay. WebAccess requires the patched headers and reports a build error
if an older dependency installation is used. The patch requires C++17 or newer; WebAccess builds with C++20.

## Code organization

| Component | Responsibility |
| --- | --- |
| `WebServer` | Owns the session lifetime, settings, workspace notifications and service construction. Its public header does not include Crow/OpenSSL. |
| `WebAccessShareModel` | Owns the share tree and model lock, workspace snapshots, directory scans, stable identities, permissions and download snapshots. |
| `WebAccessUploads` | Owns upload connections and their locks, protocol validation, acknowledgement replies and transfer cleanup. Connection keys are opaque; no socket is required. |
| `WebAccessRoutes` | Registers HTTP/WebSocket routes, applies authentication, serves assets, formats pages and streams download responses. |
| `WebAccessFileItem`, `WebAccessIds`, `WebAccessLogger` | Hold cached node data, identifier conversion and session logging without owning server lifetime. |
| `WebAccessReadFile` | Owns validated read handles and checks canonical share boundaries before previews or streaming. |
| `WebAccessActivity` | Provides synchronized active transfer snapshots and cancellation state for the desktop monitor. |
| `WebAccessHttp` | Contains Crow configuration, the HTTP application type and access middleware. |

The share model returns typed outcomes and value snapshots; HTTP status translation belongs to the routes.
The upload service has a separate registry mutex and returns protocol replies to the transport. Temporary-file
cleanup runs after releasing registry locks and never acquires the model lock. Transport events for a connection
are delivered in order. Stop joins request handlers before clearing transfers, destroying routes or releasing UI dependencies.
An injectable `IDirectoryScanner` lets concurrency tests pause or fail enumeration without exposing server internals.
Unused scan-cycle bookkeeping and presentation helpers were removed from cached nodes.

## Validation

Build `UnitTest\Units\WebAccessTests\WebAccessTests.vcxproj` in Release for x64 or Win32.
The test project uses the extension's installed static vcpkg dependencies. Override `DependencyRoot` if they are installed elsewhere.
From the repository root, run:

```powershell
.\BuildOutput\Tests\x64\Release\WebAccessTests\WebAccessTests.exe
python UnitTest\Units\WebAccessTests\IntegrationTests.py
python UnitTest\Units\WebAccessTests\ListingConcurrencyTests.py
python UnitTest\Units\WebAccessTests\LoggingTests.py
python UnitTest\Units\WebAccessTests\FeatureTests.py
node UnitTest\Units\WebAccessTests\UploaderTests.js
```

For x86, pass the Win32 executable path to the Python test scripts.
The listing suite pauses a scan deterministically while checking unrelated requests, overlapping listings,
permission changes and revocation. It also covers failed enumeration, cache identities, large folders and long paths.

`UploaderTests.js` covers the queue, acknowledgements, speed/time estimates, retries, cancellation, late callbacks
and drag-and-drop. Optional real-browser checks require Playwright (`python -m pip install playwright`) and an
installed Microsoft Edge browser:

```powershell
python UnitTest\Units\WebAccessTests\BrowserUploadTests.py
python UnitTest\Units\WebAccessTests\BrowserFeatureTests.py
```

Pass the Win32 test executable as its first argument to test the x86 server. Browser checks upload real files,
verify their contents, cancellation cleanup, live refreshes and queue preservation, and save desktop/mobile screenshots under
`BuildOutput/Tests/WebAccessBrowser`.

Native tests exercise the share model and upload protocol directly, including finalization, cleanup and permission changes.
They also check pinned read handles, 64-bit lengths and cancellation while another connection is busy,
and create the production settings, sharing-link and transfer dialogs hidden, exercise address selection and buttons,
and save QR rendering previews under `BuildOutput/Tests/WebAccessQr`. QR generation uses the locally vendored,
MIT-licensed Project Nayuki library; no external QR service is used.
The native integration harness serves only temporary test data; it never uses the user's workspace.

## Remaining limitations

Settings and share-property dialogs currently use English resource text.

## Enhancement references

These numbers remain stable so follow-up work can refer to a specific suggestion.

| Number | Enhancement | Status |
| --- | --- | --- |
| 1 | Unicode download paths, preserving streamed downloads | Implemented; regression coverage includes Unicode directories, filenames and 64-bit lengths |
| 2 | Copy sharing URL, open in browser, and QR code for phones | Implemented in the Sharing link dialog |
| 3 | Multiple-file uploads, drag-and-drop, speed and remaining time | Implemented with a sequential queue, cancel and retry |
| 4 | Separate the share model, HTTP routes and transfer handling from WebServer | Implemented with model, upload and route services |
| 5 | Move directory scanning outside the main model lock | Implemented with snapshots, overlapping refresh handling and three request workers |
| 6 | Filename search, sortable columns and readable sizes | Implemented; filter/sort survive refreshes |
| 7 | Individual upload remove/retry and duplicate filename warnings | Implemented; active transfers are protected |
| 8 | Download folders or selected files as ZIP | Suggested |
| 9 | Resumable downloads | Suggested |
| 10 | Desktop active transfer monitor and cancellation | Implemented for uploads and streamed downloads |
| 11 | Folder uploads | Suggested |
| 12 | Refresh the listing after uploads | Implemented without replacing the uploader or its results |

Additional request: inline `.txt` previews are implemented with a 1 MiB display limit.
