Ambos sirven el mismo árbol de shares que la web, con las mismas locations, permisos y usuarios (SHARES-Y-RUTAS.md). FTP: hecho (fase 4). WebDAV, cliente WebDAV y DNS-SD: hechos (fase 5).
Para los clientes con los que la web se queda corta: en Mac clásico los clientes FTP gráficos eran la forma habitual de mover ficheros, en DOS y Windows 3.1 hay clientes FTP para las pilas TCP/IP de la época, y Windows 95 trae ftp.exe.
Implementación (src/Sunfish.Core/Ftp/): FtpServer (escucha, límite por IP), FtpSession (un hilo de control por conexión; atiende ABOR mientras transfiere), DataChannel (pasivo/activo), FtpPath y FtpListing. Detalles que se han decidido al implementar:
anonymous o ftp, cualquier contraseña), pero solo ve los shares sin Users. Un share con Ftp = false no aparece en FTP.[Server]: Ftp (interruptor), FtpPort (2121), FtpPassivePorts (50000-50050; vacío o inválido = cualquier puerto libre), FtpPublicAddress (IP anunciada en PASV tras NAT) y FtpCharset (iso-8859-1 por defecto; también macroman, cp437, cp850, windows-1252, utf-8).LIST/NLST y las respuestas usan UTF-8 tras OPTS UTF8 ON y si no, el juego de la sesión; MLSD siempre UTF-8 (RFC 3659).STOR normal pasa por un temporal y renombrado (como la web); APPE y REST+STOR escriben sobre el fichero existente para reanudar, y por eso exigen Overwrite.RMD solo borra carpetas vacías (el borrado recursivo queda para la web). La raíz de un share y las carpetas virtuales no se pueden borrar, renombrar ni usar para crear.TYPE A convierte LF en CRLF al enviar; al recibir se guarda tal cual.curl (pasivo, EPSV) y con ftp.exe de Windows (activo, PORT).PASV, EPSV): rango de puertos configurable (FtpPassivePorts). Se anuncia la IP local de la conexión de control; FtpPublicAddress opcional para equipos tras NAT.PORT, EPRT): lo usan por defecto clientes antiguos como ftp.exe. El servidor solo conecta a la misma IP que abrió el control (contra el "FTP bounce") y nunca a puertos por debajo de 1024. El puerto de origen no es el 20 (no requiere privilegios); los clientes lo aceptan.EPSV/EPRT).anonymous (o ftp), con cualquier contraseña: ve los shares públicos.[User …]: ve además los shares cuyo Users lo incluye.| Grupo | Comandos |
|---|---|
| Sesión | USER PASS QUIT NOOP SYST (UNIX Type: L8) FEAT OPTS UTF8 HELP STAT |
| Navegación | PWD CWD CDUP |
| Listados | LIST (formato ls -l, el que entienden los clientes antiguos) NLST MLSD MLST |
| Transferencia | TYPE (A/I) MODE S STRU F RETR STOR APPE REST (reanudar) ABOR |
| Información | SIZE MDTM |
| Cambios | MKD RMD DELE RNFR/RNTO |
TYPE A convierte los saltos de línea a CRLF al enviar; TYPE I (binario) es el habitual.STOR sobre un fichero existente necesita Overwrite, DELE necesita Delete, etc. Las subidas también van a un temporal y se renombran al terminar.LIST como carpetas.OPTS UTF8 ON (o usa MLSD), UTF-8.dos → CP437 (o CP850), win16 → Windows-1252, mac → MacRoman.FtpCharset: iso-8859-1 (por defecto), macroman, cp437, cp850 o windows-1252.FTP no dice qué cliente se conecta, así que los perfiles de CLIENTES.md se eligen por sesión:
anonymous+dos, ana+dos, anonymous+mac… (+dos y +win16 activan alias 8.3; +mac activa la entrega en MacBinary). Funciona con cualquier cliente, porque basta con escribirlo al conectar.SITE: SITE PROFILE dos|win16|mac|none, para clientes que permiten enviar comandos.STOR con MacBinary II/III o BinHex válidos se decodifica siempre, como en la web (salvo Mac = false). Ver MAC-CLASICO.md.mac: los ficheros con ._ se listan como nombre.bin y se descargan en MacBinary. Los clientes FTP de Mac clásico suelen decodificarlo solos. Los nombres de más de 31 caracteres no se acortan en FTP (sí en las descargas web).Sobre el mismo puerto HTTP, activo por defecto en todos los shares (WebDav = false lo desactiva), para montar los shares como una carpeta desde sistemas modernos (y algunos antiguos). Es también el protocolo con el que un Sunfish explora a otro (ver más abajo).
OPTIONS, PROPFIND (profundidad 0 y 1; infinity se rechaza), PROPPATCH (se acepta y se ignora lo que no se aplica), MKCOL, GET, PUT, DELETE, COPY y MOVE dentro del mismo share.LOCK/UNLOCK simulados (se anuncia clase 2): Finder de macOS y el redirector de Windows los exigen para escribir. Se devuelven tokens válidos, pero no impiden accesos de otros clientes.displayname, resourcetype, getcontentlength, getcontenttype, getlastmodified, creationdate, getetag.DAV: 1, 2 y MS-Author-Via: DAV (la piden las "Carpetas web" de Windows 98/2000).XmlReader con DtdProcessing.Prohibit (sin entidades externas).Listing controla PROPFIND de profundidad 1.Implementación (src/Sunfish.Core/Web/WebDav.cs, dentro de WebApp; GET, HEAD y PUT son los de la web). Decisiones tomadas al implementar:
OPTIONS responde siempre (sin usuario) con DAV y MS-Author-Via; el resto exige el usuario del share como la web. Un share con WebDav = false responde 405 a los métodos DAV.PROPFIND sin cabecera Depth se trata como profundidad 1 (lo esperan varios clientes).PUT puede sustituir un fichero vacío aunque el share no tenga Overwrite: el Explorador y Finder crean primero un fichero vacío (PUT o LOCK de un recurso inexistente) y después lo rellenan.._nombre y .DS_Store (metadatos que escribe Finder) se aceptan aunque empiecen por .; no salen en los listados. Al borrar un fichero se borra también su ._.COPY/MOVE solo dentro del mismo share (si no, 502); sustituir el destino exige Delete; Overwrite: F responde 412. COPY de carpetas es recursivo y no sigue enlaces.PROPPATCH responde 200 a todo sin aplicar nada (el Explorador fija sus atributos Win32).\\equipo@puerto\DavWWWRoot): listar, leer, copiar un fichero (PUT vacío, LOCK, PUT, PROPPATCH, UNLOCK), crear carpeta y renombrar.| Cliente | Notas |
|---|---|
| Explorador de Windows 10/11 (WebClient) | Por defecto no envía Basic sin HTTPS: solo funcionan los shares públicos, salvo cambiando BasicAuthLevel en el registro. Límite de fichero de ~50 MB por defecto (FileSizeLimitInBytes) |
| Finder de macOS | Necesita LOCK; crea ficheros ._* y .DS_Store, que encajan con el almacenamiento AppleDouble |
| GVfs / gestores de Linux | dav://host:puerto/location; los servidores anunciados por DNS-SD aparecen en "Red" |
| Carpetas web de Windows 98/2000 | A probar |
| Clientes WebDAV de Mac OS 9 | A probar |
| Otro Sunfish | Explorador integrado en las aplicaciones (ver abajo) |
No se añade un protocolo propio: un Sunfish explora a otro por WebDAV, igual que lo haría un gestor de ficheros. Así funciona también con cualquier otro servidor WebDAV.
Sunfish.Core: PROPFIND, GET, PUT, MKCOL, MOVE y DELETE con HttpClient. Las aplicaciones lo usan para un panel "Explorar otro servidor" con copia en los dos sentidos (ver APLICACIONES.md)._http._tcp, _webdav._tcp y _ftp._tcp, con un registro TXT sunfish=3 y path=/.
ReuseAddress para convivir con Avahi, Bonjour o el mDNS de Windows). Se puede desactivar con Announce = false en [Server].Implementación: Dav/DavClient.cs (cliente), Net/DnsMessage.cs (mensajes DNS) y Net/Discovery.cs (MdnsAnnouncer y Discovery.BrowseAsync).
<Name> (<equipo>) y usa el nombre de host sunfish-<equipo>.local (para no pisar el del sistema). Anuncia al arrancar y responde a las preguntas; si no puede abrir el 5353, lo anota en el registro y sigue sin anunciar.sunfish-cli publicado con AOT pasa de ~4 MB a ~8 MB al incluir HttpClient y XML (cliente WebDAV).