<%@ Page Title="Strategy: Server URL import" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" %> 
<asp:Content ID="TitleContent" ContentPlaceHolderID="TitleContent" runat="server">URL import (NDJSON) - AjaxUploader v5.3 Demos</asp:Content> 
<asp:Content ID="HeaderContent" ContentPlaceHolderID="HeaderTitle" runat="server">Server URL import (NDJSON)</asp:Content> 
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server"> 
<div class="demo-card"> <div class="demo-card-header">Server-side URL import with live NDJSON progress</div> <div class="demo-card-body"> <p class="demo-description"> Paste a remote URL; the server fetches it and streams the bytes through your <code>IUploaderProvider</code>. The client sees live progress events (<code>started</code> -> <code>progress</code> -> <code>complete</code>) as newline-delimited JSON from a streaming <code>fetch()</code> response - no polling, no WebSocket. Backward-compatible: older clients that don't send <code>Accept: application/x-ndjson</code> get a single JSON response.
 </p> <div class="demo-expect"><strong>What you should see:</strong> paste a URL and the server fetches the file - it never passes through the browser at all.</div> <div class="card p-3 mt-3" style="background:#fff;border:1px solid #e2e8f0;"> <label class="form-label fw-semibold small" for="urlImportInput">Remote URL</label> <div class="d-flex flex-wrap gap-2"> <input id="urlImportInput" type="url" class="form-control" style="flex:1;min-width:20rem"
 value="https://filesamples.com/samples/image/png/sample_640%C3%97426.png"
 placeholder="https://example.com/sample.zip" /> <button id="urlImportBtn" type="button" class="btn btn-primary">Import from URL</button> </div> <div id="urlImportQueue" class="mt-3"></div> <pre id="urlImportLog" class="mt-3 p-3" role="log" aria-live="polite" style="display:none;background:#f8fafc;border:1px solid #e2e8f0;border-radius:0.5rem;max-height:16rem;overflow:auto;font-size:0.75rem;line-height:1.5;"></pre> </div> <script> (function () {
 function init() {
 if (!window.AjaxUploader || typeof AjaxUploader.create !== 'function') return; // graceful no-op if runtime missing
 var queue = document.getElementById('urlImportQueue');
 var uploader = AjaxUploader.create(queue, {
 uploadUrl: '<%= ResolveUrl("~/ajaxupload.axd/upload") %>',
 strategy: 'urlImport',
 multiple: true,
 autoUpload: true
 });
 var logEl = document.getElementById('urlImportLog');
 uploader.on('taskProgress', function (task) {
 if (!logEl) return;
 logEl.style.display = 'block';
 logEl.textContent = 'progress: ' + task.progress + '% (' + task.uploadedBytes + ' / ' + task.fileSize + ' bytes)';
 });
 uploader.on('taskComplete', function (task, result) {
 if (!logEl) return;
 logEl.style.display = 'block';
 logEl.textContent += '\ncomplete: ' + JSON.stringify(result);
 });
 var importButton = document.getElementById('urlImportBtn');
 var input = document.getElementById('urlImportInput');
 if (importButton) importButton.addEventListener('click', function () {
 var url = input ? input.value.trim() : '';
 if (url && uploader && typeof uploader.importFromUrl === 'function') uploader.importFromUrl(url);
 });
 }
 if (document.readyState !== 'loading') init();
 else document.addEventListener('DOMContentLoaded', init);
 })();
 </script> <div class="alert alert-warning mt-3" role="alert"> <strong>SSRF warning:</strong> the server fetches an arbitrary URL. In production, allow-list hosts / schemes, or wrap the <code>/import-url</code> endpoint with an <code>IHttpModule</code> that blocks internal ranges and non-http(s) schemes.
 </div> <h5 class="mt-4">Client API</h5> <div class="code-panel"> 
<pre><code><span style="color:#94a3b8">// Queue a URL import - returns the queued UploadTask.</span> 
uploader.importFromUrl('https://example.com/sample.zip', {
 fileName: 'report.zip', <span style="color:#94a3b8">// optional</span> contentType: 'application/zip' <span style="color:#94a3b8">// optional</span> 
});</code></pre> </div> <h5 class="mt-4">NDJSON wire protocol</h5> <p>Client sends <code>Accept: application/x-ndjson</code>; server streams one JSON event per line:</p> <div class="code-panel"> 
<pre><code>{"type":"started","fileName":"sample.zip","totalBytes":12345678}
{"type":"progress","loaded":1048576,"total":12345678}
{"type":"progress","loaded":2097152,"total":12345678}
...
{"type":"complete","success":true,"fileGuid":"...","fileName":"sample.zip","fileSize":12345678}</code></pre> </div> <h5 class="mt-4">Server-side fetch</h5> <p>The <code>/import-url</code> endpoint in <code>AjaxUploaderHandler</code> uses <code>HttpWebRequest</code> + <code>ProgressReportingStream</code> to emit throttled progress events during the server's fetch. Streams directly to the configured provider (filesystem by default).</p> </div> 
</div> 
</asp:Content> 
