o
    jR7                    @   s   d Z ddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
mZ ddlmZmZ ddlmZmZ G dd dZG dd	 d	eZ			dddZ			dddZdd Zedkrde  dS dS )a  
File Download Server Example

This example demonstrates how to create a secure file download server using the 
HTTPServerHandler class. The server allows:
- Listing files in a specified directory
- Downloading individual files
- Protection against directory traversal attacks

Usage:
    python fileserver.py [directory_path] [host] [port]

Example:
    python fileserver.py ./downloads 127.0.0.1 8080
    N)Path)	UniTargetUniProto)HTTPServerHandler
HTTPServerc                   @   s   e Zd ZdZ		d#ddZd$d	d
Zdd Zdd Zdd Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd  Zd!d" ZdS )%MultipartStreamProcessorz
    Memory-efficient multipart form data processor that handles boundary detection
    across chunk boundaries and streams file data directly to disk.
         @Nd   c                 C   sp   || _ || _|| _|| _|| _|| _d| _d| _d | _d | _	g | _
g | _d| _d| j  | _| j d | _|| _d S )N    looking_for_boundaryr      
s   --)boundary_bytestarget_pathmax_buffer_sizemax_file_sizeallowed_extensionsmax_files_per_requestbufferstatecurrent_file_infocurrent_file_handle
temp_filescompleted_files
file_countboundary_with_crlfend_boundaryprint_cb)selfr   r   r   r   r   r   r    r   /root/aizidognhua/tmp/workspace/projects/ec89d86c-575f-41c9-af57-ac45cbdbf775/venv/lib/python3.10/site-packages/asysocks/examples/fileserver.py__init__%   s    
z!MultipartStreamProcessor.__init__ c                    $   | j d u rd S |  |I d H  d S Nr   r   msgr   r   r    print<      
zMultipartStreamProcessor.printc                    s   |  j |7  _ g }t| j | jkr4| jdkr|  I dH  nt| j | jd kr4tdt| j  d	 | jdkrM||  I dH  | jdkrL	 |S n+| jdkr]|  I dH s\	 |S n| jdkrx| 	 I dH }|rp|
| | jdkrx	 |S q5)	z
        Process a chunk of data, returning any completed file info.
        
        Args:
            chunk (bytes): Raw chunk data
            
        Returns:
            list: List of completed file info dictionaries
        reading_file_dataN   zBuffer size exceeded:  bytesTr   reading_headers)r   lenr   r   _flush_file_data
ValueErrorextend_process_boundary_search_process_headers_process_file_dataappend)r   chunkr   	file_infor   r   r    process_chunkA   s8   




	


z&MultipartStreamProcessor.process_chunkc                    s  g }| j | j}|dkr,t| j t| jd kr*t| jd }| j | d | _ |S | j ||t| j  | jkrP|  I dH  | jrN|| j d| _|S |t| j }| j |d | _ | j drn| j dd | _ n| j dr|| j dd | _ d| _	|S )	z*Search for boundary markers in the buffer.r+   
   Nr      
   r-   )
r   findr   r.   r   _finalize_current_filer   r5   
startswithr   )r   r   boundary_pos	keep_sizeboundary_endr   r   r    r2   i   s,   z1MultipartStreamProcessor._process_boundary_searchc              
      s0  | j d}|dkr4| j d}|dkr"t| j dkr tddS | j d| }| j |d d | _ n| j d| }| j |d	 d | _ t|d
krOtdz	|jddd}W n tyk } ztd| d}~ww | |}|r| jr}|  I dH  | 	|}|std| | 
|I dH  d| _dS )zProcess multipart headers.s   

r9   s   

i    zCMultipart headers too long or malformed (missing header terminator)FNr+      i   zMultipart part headers too longutf-8strict)errorszInvalid header encoding: zInvalid or unsafe filename: r*   T)r   r=   r.   r0   decodeUnicodeDecodeError_extract_filename_from_headersr   r>   _sanitize_upload_filename_start_new_filer   )r   
header_endheader_sectionheaders_textefilenamesafe_filenamer   r   r    r3      s<   

z)MultipartStreamProcessor._process_headersc                    s   | j s	d| _dS | j| j}|dkrEt| jt| jd krCt| jt| j d }| jd| }| j|d | _| |I dH  dS | jd| }| j|d | _| |I dH  |  I dH }d| _|S )z1Process file data, looking for the next boundary.r   Nr9   r:   )r   r   r   r=   r   r.   _write_file_datar>   )r   next_boundary_pos
write_sizedata_to_writer7   r   r   r    r4      s$   z+MultipartStreamProcessor._process_file_datac                 C   sn   | dD ]/}| }| dr4td|tj}|r#|d  S td|tj}|r4|d  S qdS )z1Extract filename from Content-Disposition header.
zcontent-disposition:zfilename="([^"]*)"r<   zfilename=([^;\s]+)N)splitstriplowerr?   research
IGNORECASEgroup)r   rN   linefilename_matchr   r   r    rI      s   z7MultipartStreamProcessor._extract_filename_from_headersc                 C   s   |sdS t j|}tdd|}tdd|}tdd|}|d}|r*|dv r,dS t|d	krFt j|\}}|dd
 |dd  }|S )z^
        Sanitize uploaded filename to prevent directory traversal and other attacks.
        Nz	[<>:"|?*]_z
[^\w\-_\.]z\.\.+.z._)ra   ..         )ospathbasenamerZ   subrX   r.   splitext)r   rP   	safe_name	name_partext_partr   r   r    rJ      s   
z2MultipartStreamProcessor._sanitize_upload_filenamec              
      s  | j | jkrtd| j d| jr0tj|d  }|| jvr0td| dd| j tj| j	|}|d }zt
|d| _| j| W n+ ty` } z
td	| d
| d}~w tyu } z
td| d
| d}~ww |||dd| _|  j d7  _ dS )zStart writing a new file.zToo many files in upload (max: )r<   zFile extension 'z' not allowed. Allowed: , z
.uploadingwbzCannot create upload file '': Nz(Permission denied creating upload file 'r   )rP   	temp_path
final_pathsize)r   r   r0   r   rf   rg   rj   rY   joinr   openr   r   r5   OSErrorPermissionErrorr   )r   rP   file_ext	file_pathtemp_file_pathrO   r   r   r    rK     s2   
z(MultipartStreamProcessor._start_new_filec              
      s   | j rl|rn| jd t| }|| jkr&td| jd  d| d| j dz| j | | jd  t|7  < W d	S  tyS } ztd| jd  d| d	}~w tyk } ztd
| jd  d| d	}~ww d	S d	S )zWrite data to current file.rt   zFile 'rP   z' exceeds size limit:  bytes (max: rn   zError writing to file 'rq   NzUnexpected error writing file ')r   r   r.   r   r0   writerw   	Exception)r   datanew_sizerO   r   r   r    rR   "  s    

$z)MultipartStreamProcessor._write_file_datac                    s   | j r| j   dS dS )z'Flush file data to reduce memory usage.N)r   flush)r   r   r   r    r/   2  s   z)MultipartStreamProcessor._flush_file_datac              
      s*  | j sdS | jr| j  d| _| j d }| j d }z=t|| || jv r-| j| | j d | j d |d}| d|d  d|d d	d
I dH  | j	| d| _ |W S  t
y } z+| d| d| I dH  zt| || jv r| j| W n   Y W Y d}~nd}~ww d| _ dS )z.Finalize the current file and return its info.Nrr   rs   rP   rt   )rP   rt   rg   z[UPLOAD-SUCCESS] Uploaded: z (, bytes)z%[UPLOAD-ERROR] Error finalizing file : )r   r   closerf   renamer   remover(   r   r5   r~   unlink)r   rr   rs   r7   rO   r   r   r    r>   7  sB   



(


z/MultipartStreamProcessor._finalize_current_filec                    s   g }| j rK| jdkrK| jdkr|  I dH s	 |S n(| jdkrC| jr2| j r2| | j I dH  d| _ |  I dH }|r@|| 	 |S | j rK| jdks|S )zFinalize any remaining data.r   r-   Nr*   r   )r   r   r3   r   rR   r>   r5   )r   r   r7   r   r   r    finalizeb  s&   


z!MultipartStreamProcessor.finalizec                    s   | j rz| j   W n   Y d| _ | jD ]:}ztj|r/t| | d| I dH  W q tyP } z| d| d| I dH  W Y d}~qd}~ww | j	  dS )zClean up any temporary files.Nz$[UPLOAD-CLEANUP] Removed temp file: z*[UPLOAD-CLEANUP] Error removing temp file r   )
r   r   r   rf   rg   existsr   r(   r~   clear)r   rr   rO   r   r   r    cleanupw  s$   

(z MultipartStreamProcessor.cleanup)r   r	   Nr
   Nr"   )__name__
__module____qualname____doc__r!   r(   r8   r2   r3   r4   rI   rJ   rK   rR   r/   r>   r   r   r   r   r   r    r      s$    

(%, +r   c                       s   e Zd ZdZ		d' fdd	Zd(d	d
Zdd Zd)ddZdd Zdd Z	dd Z
dd Zd(ddZdd Zdd Zdd Zdd  Zd(d!d"Zd)d#d$Zd%d& Z  ZS )*FileDownloadHandlera0  
    HTTP server handler that provides secure file download functionality.
    
    Features:
    - File listing for GET requests without parameters
    - File download for GET requests with 'file' parameter
    - Directory traversal protection
    - MIME type detection
    - HTML directory listing
    N        r	   r
   c                    s   t    || _|| _|| _|| _|| _|| _| jr@tj	
| j| _tj	| js1td| j tj	| jsBtd| j dS dS )a  
        Initialize the file download handler.
        
        Args:
            download_directory (str): Directory to serve files from
            max_upload_size (int): Maximum total upload size per request in bytes (default: 2GB)
            max_file_size (int): Maximum individual file size in bytes (default: 500MB)
            allowed_extensions (set): Set of allowed file extensions (None = allow all)
            max_files_per_request (int): Maximum number of files per upload request (default: 100)
        z#Download directory does not exist: z"Download path is not a directory: N)superr!   download_directorymax_upload_sizer   r   r   r   rf   rg   abspathr   r0   isdir)r   r   r   r   r   r   r   	__class__r   r    r!     s   
zFileDownloadHandler.__init__r"   c                    r#   r$   r%   r&   r   r   r    r(     r)   zFileDownloadHandler.printc                    s   | j sdS |s
| j S |dd}g }|dD ]%     r# dkr$q dkr)qt fdddD r7 dS |  q|sB| j S | j }|D ]	 tj| }qGtj	|}ztj
|| j g}|| j kriW dS W |S  tyu   Y dS w )	aW  
        Sanitize the requested path to prevent directory traversal attacks while allowing
        safe navigation within the allowed directory tree.
        
        Args:
            path_request (str): The requested file or directory path
            
        Returns:
            str or None: Safe absolute path or None if invalid
        N\/ra   rb   c                 3   s    | ]}| v V  qd S r$   r   ).0char	componentr   r    	<genexpr>  s    z5FileDownloadHandler._sanitize_path.<locals>.<genexpr>):*?"<>|)r   replacerW   rX   anyr5   rf   rg   ru   r   
commonpathr0   )r   path_requestnormalized_pathpath_components	safe_pathcommon_pathr   r   r    _sanitize_path  s<   
z"FileDownloadHandler._sanitize_pathc                  C   s  | j sdS |du r| j }z|| j krd}d}ndtj|| j tjd }|}g }g }t|D ](}tj||}tj|rOtj	|}|
||f q2tj|rZ|
| q2|  |  t|}	t|}
| |}d| d }|| j krtj|d}|dkrd}tj|}|d| d	 7 }|dkrtj|dnd}|rd
| nd}d}|d| d7 }|D ]+}t|}|dkr|}n	|dd | }tj|}|d| d| d| d7 }q|D ]t\}}t|}|dkr|}n	|dd | }tj|}| |}tj|d  }|dv r"d}n*|dv r*d}n"|dv r2d}n|dv r:d}n|dv rBd}n
|dv rJd}nd}|d| d | d!| d"| d#| d$7 }qt|t| }|dg d%t| d&t| d'| d(|
 d)| d| d*| d| d+| d| d,| d| d-| d| d.| d| d/| d| d07 }|W S  ty } zt|}d1t| d2W  Y d}~S d}~ww )3z
        Generate an HTML page listing files and directories.
        
        Args:
            current_path (str): The current directory path to list
            
        Returns:
            str: HTML content
        zV<html><body><h1>File Server</h1><p>No download directory configured.</p></body></html>Nr   zRoot Directoryu$  <!DOCTYPE html>
<html>
<head>
    <title>📁 File Server - Directory Browser</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        :root {
            --primary: #2563eb;
            --primary-dark: #1d4ed8;
            --primary-light: #3b82f6;
            --secondary: #64748b;
            --secondary-light: #94a3b8;
            --success: #059669;
            --success-light: #10b981;
            --warning: #d97706;
            --warning-light: #f59e0b;
            --background: #f8fafc;
            --surface: #ffffff;
            --surface-2: #f1f5f9;
            --text: #1e293b;
            --text-muted: #64748b;
            --border: #e2e8f0;
            --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
        }
        
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: 'Inter', 'Segoe UI', system-ui, sans-serif;
            background: var(--background);
            color: var(--text);
            min-height: 100vh;
            padding: 20px;
            line-height: 1.6;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: var(--surface);
            border-radius: 12px;
            box-shadow: var(--shadow);
            overflow: hidden;
            animation: slideIn 0.5s ease-out;
        }
        @keyframes slideIn {
            from { opacity: 0; transform: translateY(20px); }
            to { opacity: 1; transform: translateY(0); }
        }
        .header {
            background: var(--primary);
            color: white;
            padding: 32px;
            text-align: center;
        }
        .header h1 {
            font-size: 2.5rem;
            font-weight: 700;
            margin-bottom: 8px;
        }
        .header p {
            opacity: 0.9;
            font-size: 1.1rem;
        }
        .breadcrumb {
            background: var(--surface-2);
            padding: 16px 32px;
            border-bottom: 1px solid var(--border);
            font-size: 1rem;
            font-weight: 500;
        }
        .content {
            padding: 32px;
        }
        .section {
            margin-bottom: 32px;
            padding: 24px;
            border-radius: 8px;
            border: 1px solid var(--border);
            background: var(--surface);
        }
        .upload-section {
            background: #f0fdf4;
            border: 2px dashed var(--success);
            transition: all 0.3s ease;
        }
        .upload-section:hover {
            background: #ecfdf5;
            border-color: var(--success-light);
        }
        .commands-section {
            background: #fefce8;
            border: 1px solid var(--warning);
        }
        .section h3 {
            color: var(--text);
            margin-bottom: 16px;
            font-weight: 600;
            font-size: 1.25rem;
        }
        .btn {
            background: var(--primary);
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 500;
            transition: all 0.2s ease;
            text-decoration: none;
            display: inline-block;
        }
        .btn:hover {
            background: var(--primary-dark);
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
        }
        .btn-upload {
            background: var(--success);
            font-size: 16px;
            padding: 16px 32px;
            border-radius: 8px;
        }
        .btn-upload:hover {
            background: var(--success-light);
            box-shadow: 0 4px 12px rgba(5, 150, 105, 0.3);
        }
        .file-input {
            padding: 12px;
            border: 2px solid var(--border);
            border-radius: 6px;
            width: 100%;
            margin-bottom: 16px;
            transition: border-color 0.2s ease;
            font-size: 14px;
        }
        .file-input:focus {
            border-color: var(--primary);
            outline: none;
            box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
        }
        .progress-container {
            display: none;
            margin-top: 16px;
            background: var(--surface-2);
            border-radius: 8px;
            padding: 16px;
        }
        .progress-bar {
            width: 100%;
            height: 8px;
            background: var(--border);
            border-radius: 4px;
            overflow: hidden;
            margin-bottom: 8px;
        }
        .progress-fill {
            height: 100%;
            background: var(--primary);
            width: 0%;
            transition: width 0.3s ease;
            border-radius: 4px;
        }
        .command-box {
            background: #0f172a;
            color: #e2e8f0;
            padding: 16px;
            border-radius: 6px;
            font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
            font-size: 13px;
            margin: 12px 0;
            position: relative;
            overflow-x: auto;
            border: 1px solid #334155;
        }
        .command-box pre {
            margin: 0;
            padding: 0;
            background: transparent;
            color: inherit;
            font-family: inherit;
            font-size: inherit;
            line-height: 1.5;
            white-space: pre-wrap;
            word-wrap: break-word;
        }
        .copy-btn {
            position: absolute;
            top: 12px;
            right: 12px;
            background: var(--secondary);
            color: white;
            border: none;
            padding: 6px 12px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 11px;
            transition: background 0.2s;
        }
        .copy-btn:hover { 
            background: var(--secondary-light); 
        }
        .table-container {
            overflow-x: auto;
            border-radius: 8px;
            border: 1px solid var(--border);
        }
        table {
            width: 100%;
            border-collapse: collapse;
            background: var(--surface);
        }
        th {
            background: var(--surface-2);
            color: var(--text);
            padding: 16px;
            text-align: left;
            font-weight: 600;
            font-size: 14px;
            border-bottom: 1px solid var(--border);
        }
        td {
            padding: 12px 16px;
            border-bottom: 1px solid var(--border);
            transition: background-color 0.2s ease;
        }
        tr:hover td {
            background-color: var(--surface-2);
        }
        .file-link {
            color: var(--primary);
            text-decoration: none;
            font-weight: 500;
            transition: color 0.2s ease;
        }
        .file-link:hover {
            color: var(--primary-dark);
        }
        .stats {
            background: var(--surface-2);
            padding: 24px;
            border-radius: 8px;
            text-align: center;
            margin-top: 24px;
            border: 1px solid var(--border);
        }
        .stats h3 {
            color: var(--text);
            margin-bottom: 20px;
        }
        .stat-item {
            text-align: center;
            margin: 12px;
        }
        .stat-number {
            font-size: 2rem;
            font-weight: 700;
            margin-bottom: 4px;
        }
        .stat-label {
            font-size: 14px;
            color: var(--text-muted);
            font-weight: 500;
        }
        .tab-container {
            margin-bottom: 20px;
        }
        .tab-buttons {
            display: flex;
            background: var(--surface-2);
            border-radius: 6px;
            padding: 4px;
            margin-bottom: 16px;
        }
        .tab-btn {
            flex: 1;
            padding: 10px 16px;
            border: none;
            background: transparent;
            cursor: pointer;
            border-radius: 4px;
            transition: all 0.2s ease;
            font-weight: 500;
            font-size: 14px;
            color: var(--text-muted);
        }
        .tab-btn.active {
            background: var(--surface);
            color: var(--text);
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
        }
        .tab-content {
            display: none;
        }
        .tab-content.active {
            display: block;
        }
        .badge {
            padding: 4px 8px;
            border-radius: 12px;
            font-size: 12px;
            font-weight: 500;
        }
        .badge-directory {
            background: #dbeafe;
            color: #1e40af;
        }
        .badge-file {
            background: #f3e8ff;
            color: #7c3aed;
        }
        @media (max-width: 768px) {
            .container { margin: 10px; }
            .content { padding: 20px; }
            .header { padding: 24px; }
            .header h1 { font-size: 2rem; }
            .stats > div { flex-direction: column; }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="breadcrumb">
            <strong>📍 Current Location:</strong> z.
        </div>
        <div class="content">
r"   z@            <div class="section">
                <a href="?dir=u   " class="btn" style="text-decoration: none; display: inline-block;">
                    ⬆️ Back to Parent Directory
                </a>
            </div>
z?dir=zhttp://YOUR_SERVER_IP:8080u   
            <div class="section upload-section">
                <h3>📤 Upload Files</h3>
                <form id="uploadForm" method="post" enctype="multipart/form-data" action="u;  ">
                    <input type="file" name="files" multiple accept="*/*" class="file-input" id="fileInput">
                    <button type="submit" class="btn btn-upload">🚀 Upload Files</button>
                    <div class="progress-container" id="progressContainer">
                        <div class="progress-bar">
                            <div class="progress-fill" id="progressFill"></div>
                        </div>
                        <div id="progressText">Uploading... 0%</div>
                    </div>
                </form>
                <div style="margin-top: 15px; font-size: 14px; color: #2d5a27;">
                    💡 Drag and drop files or click to browse. Multiple files supported. Large files streamed efficiently.
                </div>
            </div>

            <div class="section">
                <h3>📂 Directory Contents</h3>
                <div class="table-container">
                    <table>
                        <thead>
                            <tr>
                                <th>📋 Name</th>
                                <th>📁 Type</th>
                                <th>📏 Size</th>
                                <th>🕒 Actions</th>
                            </tr>
                        </thead>
                        <tbody>
zS                            <tr>
                                <td><a href="?dir=u   " class="file-link">📁 z</a></td>
                                <td><span class="badge badge-directory">Directory</span></td>
                                <td style="text-align: right;">-</td>
                                <td><a href="?dir=z" class="btn" style="padding: 6px 12px; font-size: 12px; text-decoration: none;">Browse</a></td>
                            </tr>
r<   )z.jpgz.jpegz.pngz.gifz.bmpu   🖼️)z.mp4z.aviz.mkvz.movu   🎬)z.mp3z.wavz.flacz.oggu   🎵)z.pdfu   📕)z.txtz.mdu   📄)z.zipz.rarz.7zz.tarz.gzu   📦zT                            <tr>
                                <td><a href="?file=z" class="file-link"> z</a></td>
                                <td><span class="badge badge-file">File</span></td>
                                <td style="text-align: right;">z9</td>
                                <td><a href="?file=z" class="btn" style="padding: 6px 12px; font-size: 12px; text-decoration: none;">Download</a></td>
                            </tr>
u                          </tbody>
                    </table>
                </div>
            </div>
            
            <div class="stats">
                <h3>📊 Directory Statistics</h3>
                <div style="display: flex; justify-content: space-around; flex-wrap: wrap; margin-top: 16px;">
                    <div class="stat-item">
                        <div class="stat-number" style="color: var(--success);">u   </div>
                        <div class="stat-label">📁 Directories</div>
                    </div>
                    <div class="stat-item">
                        <div class="stat-number" style="color: var(--primary);">u   </div>
                        <div class="stat-label">📄 Files</div>
                    </div>
                    <div class="stat-item">
                        <div class="stat-number" style="color: var(--secondary);">ue  </div>
                        <div class="stat-label">📋 Total Items</div>
                    </div>
                </div>
                <div style="margin-top: 16px; font-size: 14px; color: var(--text-muted);">
                    💾 Current path: <code style="background: var(--surface-2); padding: 2px 6px; border-radius: 4px; font-size: 13px;">u  </code>
                </div>
            </div>

            <div class="section commands-section">
                <h3>💻 Command Line Upload Examples</h3>
                <p style="margin-bottom: 20px; color: var(--text-muted);">Use these commands to upload files from your terminal or scripts.</p>
                <div class="tab-container">
                    <div class="tab-buttons">
                        <button class="tab-btn active" onclick="showTab('curl')">🌐 cURL</button>
                        <button class="tab-btn" onclick="showTab('wget')">📥 wget</button>
                        <button class="tab-btn" onclick="showTab('powershell')">⚡ PowerShell</button>
                        <button class="tab-btn" onclick="showTab('python')">🐍 Python</button>
                    </div>
                    
                    <div id="curl" class="tab-content active">
                        <div class="command-box">
                            <button class="copy-btn" onclick="copyToClipboard('curlCmd')">📋 Copy</button>
                            <pre id="curlCmd"># Upload a single file
curl -X POST -F "files=@/path/to/your/file.txt" "z{"

# Upload multiple files
curl -X POST \
  -F "files=@file1.txt" \
  -F "files=@file2.jpg" \
  -F "files=@file3.pdf" \
  "uV  "</pre>
                        </div>
                        <p><strong>Usage:</strong> Replace <code>/path/to/your/file.txt</code> with your actual file path. Use <code>-F "files=@filename"</code> for each file.</p>
                    </div>
                    
                    <div id="wget" class="tab-content">
                        <div class="command-box">
                            <button class="copy-btn" onclick="copyToClipboard('wgetCmd')">📋 Copy</button>
                            <pre id="wgetCmd"># Create multipart form data (limited support)
echo -e "--boundary123\r\nContent-Disposition: form-data; name=\"files\"; filename=\"test.txt\"\r\nContent-Type: text/plain\r\n\r\nfile content here\r\n--boundary123--\r\n" | \
wget --post-data=@- \
     --header="Content-Type: multipart/form-data; boundary=boundary123" \
     "u  " -O -</pre>
                        </div>
                        <p><strong>Note:</strong> wget has limited multipart support. <strong>Recommended:</strong> Use cURL for better compatibility and easier syntax.</p>
                    </div>
                    
                    <div id="powershell" class="tab-content">
                        <div class="command-box">
                            <button class="copy-btn" onclick="copyToClipboard('psCmd')">📋 Copy</button>
                            <pre id="psCmd"># Upload a single file
$file = Get-Item "C:\path\to\your\file.txt"
$form = @{'files' = $file}
$response = Invoke-RestMethod -Uri "z" -Method Post -Form $form
Write-Output $response

# Upload multiple files
$files = Get-ChildItem "C:\path\to\files\*" -Include *.txt,*.jpg,*.pdf
$form = @{}
foreach ($file in $files) {
    $form.Add("files", $file)
}
$response = Invoke-RestMethod -Uri "u  " -Method Post -Form $form
Write-Output $response</pre>
                        </div>
                        <p><strong>Usage:</strong> Replace the file paths with your actual Windows file paths. Works with PowerShell 3.0+.</p>
                    </div>
                    
                    <div id="python" class="tab-content">
                        <div class="command-box">
                            <button class="copy-btn" onclick="copyToClipboard('pythonCmd')">📋 Copy</button>
                            <pre id="pythonCmd">#!/usr/bin/env python3
import requests
import os

# Upload a single file
def upload_single_file(file_path):
    url = "a7  "
    with open(file_path, 'rb') as f:
        files = {'files': f}
        response = requests.post(url, files=files)
        print(f"Status: {response.status_code}")
        print(f"Response: {response.text}")
        return response

# Upload multiple files
def upload_multiple_files(file_paths):
    url = "u  "
    files = []
    try:
        for file_path in file_paths:
            files.append(('files', open(file_path, 'rb')))
        
        response = requests.post(url, files=files)
        print(f"Status: {response.status_code}")
        print(f"Response: {response.text}")
        return response
    finally:
        # Close all file handles
        for _, file_handle in files:
            file_handle.close()

# Example usage
if __name__ == "__main__":
    # Single file upload
    upload_single_file("/path/to/your/file.txt")
    
    # Multiple files upload
    file_list = [
        "/path/to/file1.txt",
        "/path/to/file2.jpg",
        "/path/to/file3.pdf"
    ]
    upload_multiple_files(file_list)</pre>
                        </div>
                        <p><strong>Installation:</strong> <code>pip install requests</code><br>
                        <strong>Usage:</strong> Replace file paths with your actual file paths. The script includes proper error handling and file cleanup.</p>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        // Tab switching functionality
        function showTab(tabName) {
            const contents = document.querySelectorAll('.tab-content');
            contents.forEach(content => content.classList.remove('active'));
            
            const buttons = document.querySelectorAll('.tab-btn');
            buttons.forEach(btn => btn.classList.remove('active'));
            
            document.getElementById(tabName).classList.add('active');
            event.target.classList.add('active');
        }
        
        // Copy to clipboard functionality
        function copyToClipboard(elementId) {
            const element = document.getElementById(elementId);
            const text = element.textContent;
            
            if (navigator.clipboard) {
                navigator.clipboard.writeText(text).then(() => {
                    showCopyFeedback(event.target);
                });
            } else {
                const textArea = document.createElement('textarea');
                textArea.value = text;
                document.body.appendChild(textArea);
                textArea.select();
                document.execCommand('copy');
                document.body.removeChild(textArea);
                showCopyFeedback(event.target);
            }
        }
        
        function showCopyFeedback(button) {
            const originalText = button.textContent;
            button.textContent = '✅ Copied!';
            button.style.background = '#28a745';
            setTimeout(() => {
                button.textContent = originalText;
                button.style.background = '#4a5568';
            }, 2000);
        }
        
        // Upload progress functionality
        document.getElementById('uploadForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const fileInput = document.getElementById('fileInput');
            const files = fileInput.files;
            
            if (files.length === 0) {
                alert('Please select files to upload');
                return;
            }
            
            const formData = new FormData();
            for (let i = 0; i < files.length; i++) {
                formData.append('files', files[i]);
            }
            
            const progressContainer = document.getElementById('progressContainer');
            const progressFill = document.getElementById('progressFill');
            const progressText = document.getElementById('progressText');
            
            progressContainer.style.display = 'block';
            
            const xhr = new XMLHttpRequest();
            
            xhr.upload.addEventListener('progress', function(e) {
                if (e.lengthComputable) {
                    const percentComplete = (e.loaded / e.total) * 100;
                    progressFill.style.width = percentComplete + '%';
                    progressText.textContent = `Uploading... ${Math.round(percentComplete)}% (${formatBytes(e.loaded)} / ${formatBytes(e.total)})`;
                }
            });
            
            xhr.addEventListener('load', function() {
                if (xhr.status === 200) {
                    progressText.textContent = 'Upload complete! Redirecting...';
                    setTimeout(() => {
                        location.reload();
                    }, 1500);
                } else {
                    progressText.textContent = 'Upload failed!';
                    progressFill.style.background = '#ef4444';
                }
            });
            
            xhr.addEventListener('error', function() {
                progressText.textContent = 'Upload error!';
                progressFill.style.background = '#ef4444';
            });
            
            xhr.open('POST', this.action);
            xhr.send(formData);
        });
        
        function formatBytes(bytes) {
            if (bytes === 0) return '0 Bytes';
            const k = 1024;
            const sizes = ['Bytes', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
        }
        
        // Drag and drop functionality
        const fileInput = document.getElementById('fileInput');
        const uploadSection = document.querySelector('.upload-section');
        
        ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
            uploadSection.addEventListener(eventName, preventDefaults, false);
        });
        
        function preventDefaults(e) {
            e.preventDefault();
            e.stopPropagation();
        }
        
        ['dragenter', 'dragover'].forEach(eventName => {
            uploadSection.addEventListener(eventName, highlight, false);
        });
        
        ['dragleave', 'drop'].forEach(eventName => {
            uploadSection.addEventListener(eventName, unhighlight, false);
        });
        
        function highlight(e) {
            uploadSection.style.background = '#ecfdf5';
            uploadSection.style.borderColor = 'var(--success-light)';
            uploadSection.style.transform = 'scale(1.02)';
        }
        
        function unhighlight(e) {
            uploadSection.style.background = '#f0fdf4';
            uploadSection.style.borderColor = 'var(--success)';
            uploadSection.style.transform = 'scale(1)';
        }
        
        uploadSection.addEventListener('drop', handleDrop, false);
        
        function handleDrop(e) {
            const dt = e.dataTransfer;
            const files = dt.files;
            fileInput.files = files;
            
            if (files.length > 0) {
                const fileCount = files.length;
                const totalSize = Array.from(files).reduce((sum, file) => sum + file.size, 0);
                alert(`Ready to upload ${fileCount} file(s) (${formatBytes(totalSize)} total)`);
            }
        }
    </script>
</body>
</html>z7<html><body><h1>Error</h1><p>Failed to list directory: </p></body></html>)r   rf   rg   relpathr   seplistdirru   isfilegetsizer5   r   sorthtmlescape_generate_breadcrumbsdirnamerstripurllibparsequotelstrip_format_file_sizerj   rY   r.   r~   str) r   current_pathrelative_pathdisplay_pathfilesdirectoriesitem	item_pathrt   escaped_directoryescaped_display_pathbreadcrumbshtml_contentparent_relativeencoded_parentcurrent_dir_encodedcurrent_dir_param
server_urlr   escaped_dirnamedir_pathencoded_dirnamerP   escaped_filenamerz   encoded_filenamesize_strry   icontotal_itemsrO   	error_msgr   r   r    _generate_directory_list_html  s&  





  E    E    
K
"
	







	))00<<GGPP__ii  *z1FileDownloadHandler._generate_directory_list_htmlc           	      C   s   |dkrdS dg}| dd}d}t|D ]:\}}|sq||r%d| n|7 }tj|}t|}|t|d krE|	d| d q|	d| d| d	 qd

|S )z
        Generate breadcrumb navigation HTML.
        
        Args:
            relative_path (str): The current relative path
            
        Returns:
            str: HTML breadcrumb navigation
        r   uH   <a href="?" style="text-decoration: none; color: #0066cc;">🏠 Root</a>r"   r<   u    <span style="color: #333;">📁 z</span>z<a href="?dir=u6   " style="text-decoration: none; color: #0066cc;">📁 z</a>u'    <span style="color: #999;">→</span> )rX   rW   	enumerater   r   r   r   r   r.   r5   ru   )	r   r   r   partsr   ipartencoded_pathescaped_partr   r   r    r     s   


z)FileDownloadHandler._generate_breadcrumbsc                 C   s   t |\}}|p
dS )z
        Get the MIME type for a file.
        
        Args:
            filepath (str): Path to the file
            
        Returns:
            str: MIME type
        zapplication/octet-stream)	mimetypes
guess_type)r   filepath	mime_typer`   r   r   r    _get_mime_type%  s   
z"FileDownloadHandler._get_mime_typec              
      s   zTt j|jd}t j|j}d|v r.|d r.|d d }| ||jI dH  W dS d|v rK|d d r>|d d nd}| 	|I dH  W dS | 	dI dH  W dS  t
yv } z| ddt| I dH  W Y d}~dS d}~ww )	z
        Handle GET requests for file listing, directory browsing, and downloads.
        
        Args:
            event: The HTTP request event
        asciifiler   Ndirr"     zInternal Server Error: )r   r   urlparsetargetrG   parse_qsquery_serve_fileheaders_serve_directory_listr~   _serve_errorr   )r   event	url_partsquery_paramsrz   r   rO   r   r   r    do_GET2  s   *zFileDownloadHandler.do_GETc              
      s   z&t j|jd}t j|j}|ddgd }| ||I dH  W dS  t	yH } z| 
ddt| I dH  W Y d}~dS d}~ww )zy
        Handle POST requests for file uploads.
        
        Args:
            event: The HTTP request event
        r   r   r"   r   Nr   zUpload Error: )r   r   r   r   rG   r   r   get_handle_file_uploadr~   r   r   )r   r   r   r   
target_dirrO   r   r   r    do_POSTN  s   *zFileDownloadHandler.do_POSTc              
      s  z|  |}|rtj|s| ddI dH  W dS d}d}|jD ]\}}| dkr2|d}q"| dkr?t|d}q"|rG|	dsS| ddI dH  W dS |sa| dd	I dH  W dS t
d
|}|su| ddI dH  W dS |dd}	d|	 d}
d|	 dd}| ||
||I dH  W dS  ty } z | d| I dH  | ddt| I dH  W Y d}~dS d}~ww )z
        Handle multipart file upload with memory-efficient streaming.
        
        Args:
            event: The HTTP request event
            target_dir (str): Target directory for upload (relative to download_directory)
          zInvalid target directoryNs   content-typer   s   content-lengthzmultipart/form-dataz.Only multipart/form-data uploads are supportedzContent-Length header requiredzboundary=([^;]+)z Missing boundary in Content-Typer<   r   z--z[UPLOAD-ERROR] r   zUpload processing error: )r   rf   rg   r   r   r   rY   rG   intr?   rZ   r[   r]   rX   encode_process_multipart_uploadr~   r(   r   )r   r   r   safe_target_pathcontent_typecontent_lengthnamevalueboundary_matchboundaryr   end_boundary_bytesrO   r   r   r    r   b  sB   
*z'FileDownloadHandler._handle_file_uploadc              
      s  g }d}d}d}|| j krtd| d| j  dt|||| j| j| j| jd}	zl||k r~|| }
t||
}| |I dH }|sBn<|t	|7 }|	
|I dH }|| |d	krz|| d
 }|d dkrz| d|dd|dd|ddI dH  ||k s.|	 I dH }|| | ||I dH  W dS  ty } z'| d| I dH  |	 I dH  | ddt| I dH  W Y d}~dS d}~w ty } z"| d| I dH  |	 I dH  | ddI dH  W Y d}~dS d}~w ty( } z'| d| I dH  |	 I dH  | ddt| I dH  W Y d}~dS d}~w ty[ } z'| d| I dH  |	 I dH  | ddt| I dH  W Y d}~dS d}~ww )aJ  
        Process multipart upload data with streaming to avoid memory issues.
        
        Args:
            target_path (str): Safe target directory path
            boundary_bytes (bytes): Multipart boundary
            end_boundary_bytes (bytes): End boundary
            content_length (int): Total content length
        r   i   r   zUpload too large: r|   rn   )r   r   r   r   N   r
   z[UPLOAD-PROGRESS] .1f% (r   r   r   z[UPLOAD-VALIDATION] r   zUpload validation failed: z[UPLOAD-MEMORY] Out of memory: i  z&Upload too large - insufficient memoryz[UPLOAD-DISK] Disk error: i  zServer storage error: z![UPLOAD-ERROR] Unexpected error: r   zUpload processing failed: )r   r0   r   r   r   r   r   min_read_upload_chunkr.   r8   r1   r(   r   _send_upload_success_responser   r   r   MemoryErrorrw   r~   )r   r   r   r	  r  uploaded_filesbytes_processed
chunk_sizer   	processor	remaining	read_sizer6   
file_infosprogressfinal_filesrO   r   r   r    r    sn   




*
* **z-FileDownloadHandler._process_multipart_uploadc              
      s  z:t j| j ddI dH }t|tjr#|jr |jd| W S dW S t|tjr,W dS | 	dt
| I dH  W dS  t jyO   | 	dI dH  td tyl } z| 	d| I dH  td	| d}~w ty } z| 	d
| I dH  td| d}~ww )zQ
        Read a chunk of upload data from the HTTP request with timeout.
        g      >@)timeoutNr   z&[UPLOAD-ERROR] Unexpected event type: z*[UPLOAD-ERROR] Timeout reading upload dataz$Upload timeout - connection too slowz![UPLOAD-ERROR] Connection error: zUpload connection lost: z$[UPLOAD-ERROR] Error reading chunk: zError reading upload data: )asynciowait_for_wrapper
next_event
isinstanceh11Datar   EndOfMessager(   typeTimeoutErrorrw   ConnectionErrorr~   )r   rt   r   rO   r   r   r    r    s*   z&FileDownloadHandler._read_upload_chunkc              
      s^  z|| j kr
d}ntj|| j tjd}dtj| dt	| d}|D ]}| 
|d }|dt|d  d	| d
7 }q(|dtj| d 7 }|d}|  }|dddfdtt	|dfg tjd|d}	| j|	I dH  | jtj|dI dH  | jt I dH  W dS  ty }
 z| d|
 I dH   d}
~
ww )z
        Send a success response after file upload.
        
        Args:
            uploaded_files (list): List of uploaded file info
            target_path (str): Target directory path
        r"   r   zv<!DOCTYPE html>
<html>
<head>
    <title>Upload Successful</title>
    <meta http-equiv="refresh" content="3;url=?dir=u   ">
</head>
<body style="font-family: Arial, sans-serif; margin: 40px;">
    <h1>✅ Upload Successful!</h1>
    <p>Successfully uploaded z file(s):</p>
    <ul>
rt   u           <li>📄 <strong>rP   z</strong> (z)</li>
z`    </ul>
    <p>Redirecting back to directory listing in 3 seconds...</p>
    <p><a href="?dir=zD">Click here if not redirected automatically</a></p>
</body>
</html>rD   Content-Typetext/html; charset=utf-8r   Content-Length   status_coder   Nr   z/[UPLOAD-ERROR] Error sending success response: )r   rf   rg   r   r   r   r   r   r   r.   r   r   r   r   basic_headersr1   r   r   Responser  sendr!  r"  r~   r(   )r   r  r   redirect_pathr   r7   r   bodyr   responserO   r   r   r    r    sB   

"

z1FileDownloadHandler._send_upload_success_responsec                 C   sR   |dkr|d ddS |dkr|d ddS |dkr$|d ddS | dS )	z*Format file size in human-readable format.i   @r  z GBr    MB   z KBr,   r   )r   rt   r   r   r    r   4  s   
z%FileDownloadHandler._format_file_sizec              
      sP  z|  |}|s| ddI dH  W dS tj|s'| ddI dH  W dS tj|s9| ddI dH  W dS | |}|d}|  }|	dd	d
fdt
t|d
fg tjd|d}| j|I dH  | jtj|dI dH  | jt I dH  W dS  ty } z| ddt
| I dH  W Y d}~dS d}~ww )z
        Serve the HTML directory listing page.
        
        Args:
            dir_path (str): The directory path to list (relative to download_directory)
        r   zInvalid directory pathN  zDirectory not foundzNot a directoryrD   r&  r'  r   r(  r)  r*  r,  r   z!Error generating directory list: )r   r   rf   rg   r   r   r   r   r-  r1   r   r.   r   r.  r  r/  r!  r"  r~   )r   r   r   r   r1  r   r2  rO   r   r   r    r   ?  s6   


*z)FileDownloadHandler._serve_directory_listc                    sn  |  |}|s| ddI dH  dS tj|s$| ddI dH  dS tj|s5| ddI dH  dS z^tj|}| |}d}|rZ|D ]\}}| dkrY|	d} nqHd	}	|d
 }
d}|r|
drz"|dd }d|v r|dd
\}}|rt|}	|rt|}
d}W n ttfy   Y nw |
|	 d
 }|  }|d|dfdt|dfdddtj| ddfg |dkr|dd|	 d|
 d| df tj||d}| j|I dH  d}d	}|}t|d}|	d	kr||	 |d	krwt||}||}|snezB| jtj|dI dH  |t|7 }|t|8 }|dkrS|d d	krS|| d }| d |d!d"|d#d|d#d$I dH  W n t yq } z| d%|d#d&| I dH   d}~ww |d	ksW d   n	1 sw   Y  | jt! I dH  W dS  t y } z| d'd(t| I dH  W Y d}~dS d}~ww ))a  
        Serve a specific file for download with support for large files.
        
        Args:
            file_path (str): The requested file path (can include directories)
            request_headers (dict): HTTP request headers for range support
        r   zInvalid filenameNr5  zFile not foundz
Not a files   ranger   r   r<   r)  zbytes=   -   r&  r(  )zAccept-Rangess   byteszContent-Dispositionzattachment; filename="r   zContent-Rangezbytes r   r*  i   rbr,  i  @r
  r
   z![FILE-SERVER] Download progress: r  r  r   r   z%[FILE-SERVER] Error sending chunk at z bytes: r   zError serving file: )"r   r   rf   rg   r   r   r   r   rY   rG   r?   rW   r   r0   
IndexErrorr-  r1   r   r   rh   r5   r   r.  r  r/  rv   seekr  readr!  r.   r(   r~   r"  )r   rz   request_headersr   	file_sizer   range_headerr  r  
start_byteend_byter+  
range_specstartendr  r   r2  r  
bytes_sentbytes_remainingfr  r6   r  rO   r   r   r    r   g  s   
	

&



*
*zFileDownloadHandler._serve_filec              
      s   zSd| dt | dd}|  }|dddfdtt|dfg tj||d	}| j	
|I d
H  | j	
tj|dI d
H  | j	
t I d
H  W d
S  tyr } z| d| I d
H  W Y d
}~d
S d
}~ww )z
        Serve an error response.
        
        Args:
            status_code (int): HTTP status code
            message (str): Error message
        z<html><body><h1>Error z</h1><p>r   rD   r&  r'  r   r(  r*  Nr,  zError serving error response: )r   r   r   r-  r1   r   r.   r   r.  r  r/  r!  r"  r~   r(   )r   r+  messager1  r   r2  rO   r   r   r    r     s    $z FileDownloadHandler._serve_error)Nr   r	   Nr
   Nr   r$   )r   r   r   r   r!   r(   r   r   r   r   r   r   r   r  r  r  r   r   r   r   __classcell__r   r   r   r    r     s4    

7      $
1O7

(nr   r   r	   r
   c           
   
      sb   z fdd}t || |d}| I dH W S  ty0 }	 z
d|	fW  Y d}	~	S d}	~	ww )aD  
    Run the file download server from a target.
    
    Args:
        target: Server target configuration
        download_directory (str): Directory to serve files from
        log_callback: Logging callback function
        max_upload_size (int): Maximum total upload size per request in bytes (default: 2GB)
        max_file_size (int): Maximum individual file size in bytes (default: 500MB)
        allowed_extensions (set): Set of allowed file extensions (None = allow all)
        max_files_per_request (int): Maximum number of files per upload request (default: 100)
    c                      s   t  dS )Nr   r   r   r   )r   r   r   r   r   r   r   r   r    <lambda>  s    z-run_file_server_from_target.<locals>.<lambda>)log_callbackN)r   server~   )
r   r   rM  r   r   r   r   handler_factoryserverrO   r   rK  r    run_file_server_from_target  s   rQ  	127.0.0.1  Fc              
      s<  zzZd}|rdd }| r#t d| d|  t dtj|   nt d| d| d |r4t d t||tj}	t|	| |||||d	I dH \}
}|durVt d
|  |
I dH  W n% tyi   t d Y n t	y } zt d
|  W Y d}~nd}~ww W |
dur|

  t d dS |
dur|

  t d w )aM  
    Run the file download server.
    
    Args:
        download_directory (str): Directory to serve files from
        host (str): Host to bind to
        port (int): Port to bind to
        debug (bool): Enable debug logging
        max_upload_size (int): Maximum total upload size per request in bytes (default: 2GB)
        max_file_size (int): Maximum individual file size in bytes (default: 500MB)
        allowed_extensions (set): Set of allowed file extensions (None = allow all)
        max_files_per_request (int): Maximum number of files per upload request (default: 100)
    Nc                    s   t d|   d S )Nz[FILE-SERVER] )r(   )r'   r   r   r    rM    s   z%run_file_server.<locals>.log_callbackzStarting file server on r   zServing files from: z (no download directory)z+Debug mode enabled - verbose logging active)r   rM  r   r   r   r   zServer error: 
Server stopped by userzServer stopped)r(   rf   rg   r   r   r   
SERVER_TCPrQ  KeyboardInterruptr~   cancel)r   hostportdebugr   r   r   r   rM  r   server_taskerrrO   r   r   r    run_file_server
  sJ   	
r]  c                  C   sl  ddl } ddl}| jd| jdd}|jdddd	 |jd
dddd |jddtddd |jddddd |jdtddd |jdtddd |jdtd d!d |jd"td#d$ |jd%d&d'd(d) | }|jrt	j
|js}td*|j d+ |d, t	j
|jstd-|j d. |d, |jd,k s|jd/krtd0|j  |d, |jd1k rtd2|j  |d, |jd1k rtd3|j  |d, |jd,k rtd4|j  |d, d}|jrt }|jd5D ]}| }|d6sd6| }||  qtd7 td8 |jrtd9t	j
|j  ntd: td;|j d<|j  |jr6td= td>|jd? d@dA tdB|jd? d@dA tdC|j  |rftdDdEt|  ntdF td8 zt t!|j|j|j|j|j|j||jdG W dS  t"y   tdH Y dS  t#y } ztdI|  |d, W Y d}~dS d}~ww )Jz/
    Main entry point for the file server.
    r   NzLAsysocks File Server - Secure file upload/download server with web interfaceu  
Examples:
  %(prog)s                                    # Start server on 127.0.0.1:8080 (no directory)
  %(prog)s /home/user/files                  # Serve files from directory
  %(prog)s /home/user/files --host 0.0.0.0  # Bind to all interfaces
  %(prog)s /home/user/files --port 9000      # Use custom port
  %(prog)s /home/user/files --debug          # Enable debug logging
  %(prog)s --help                           # Show this help message

Features:
  • Modern web interface with drag-and-drop uploads
  • Directory browsing with breadcrumb navigation
  • Real-time upload progress bars
  • Command-line examples (cURL, wget, PowerShell, Python)
  • Secure file handling with directory traversal protection
  • Large file streaming support
        )descriptionformatter_classepilog	directoryr   z(Directory to serve files from (optional))nargshelpz--hostz-HrR  z$Host to bind to (default: 127.0.0.1))defaultrc  z--portz-prS  zPort to bind to (default: 8080))r#  rd  rc  z--debugz-d
store_truez5Enable debug logging (shows detailed server activity))actionrc  z--max-upload-sizer   z=Maximum total upload size per request in bytes (default: 2GB)z--max-file-sizer	   z6Maximum individual file size in bytes (default: 500MB)z--max-filesr
   z9Maximum number of files per upload request (default: 100)z--allowed-extensionszHComma-separated list of allowed file extensions (e.g., ".txt,.jpg,.pdf"))r#  rc  z	--versionz-vversionzAsysocks File Server 1.0.0)rf  rg  zError: Directory 'z' does not existr<   zError: 'z' is not a directoryi  z-Error: Port must be between 1 and 65535, got r4  z8Error: max-upload-size must be at least 1024 bytes, got z6Error: max-file-size must be at least 1024 bytes, got z)Error: max-files must be at least 1, got r   ra   zAsysocks File Serverz2==================================================zDirectory: z"Directory: None (upload-only mode)zAddress: http://r   zDebug: EnabledzMax upload size: r   z.0fr3  zMax file size: zMax files per request: zAllowed extensions: ro   zAllowed extensions: AllrJ  rT  zFailed to start server: )$argparsesysArgumentParserRawDescriptionHelpFormatteradd_argumentr   r   
parse_argsra  rf   rg   r   r(   exitr   rY  r   r   	max_filesr   setrW   rX   r?   addrY   r   rX  rZ  ru   sortedr  runr]  rV  r~   )rh  ri  parserargsr   extrO   r   r   r    mainA  s   










rw  __main__)NNr   r	   Nr
   )NrR  rS  Fr   r	   Nr
   )r   r  rf   urllib.parser   r   r   r   tempfilerZ   pathlibr   asysocks.unicomm.common.targetr   r   0asysocks.unicomm.protocol.server.http.httpserverr   r   r   r   rQ  r]  rw  r   r   r   r   r    <module>   sN     n          m

7 
