Newer
Older
Sunfish / DOC / FTP-Y-WEBDAV.md
@Ivan Dominguez Ivan Dominguez 21 hours ago 10 KB 3.0

FTP y WebDAV

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).

FTP

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:

  • Anónimo siempre permitido (anonymous o ftp, cualquier contraseña), pero solo ve los shares sin Users. Un share con Ftp = false no aparece en FTP.
  • Opciones en [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).
  • Juego de caracteres: lo que llega se lee como UTF-8 si es válido y, si no, con el juego de la sesión. 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.
  • Probado con curl (pasivo, EPSV) y con ftp.exe de Windows (activo, PORT).

Conexión

  • Puerto de control: 2121 por defecto (el 21 requiere privilegios en Linux/macOS), configurable.
  • Modo pasivo (PASV, EPSV): rango de puertos configurable (FtpPassivePorts). Se anuncia la IP local de la conexión de control; FtpPublicAddress opcional para equipos tras NAT.
  • Modo activo (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.
  • IPv4 e IPv6 (EPSV/EPRT).
  • Sin cifrado (ni FTPS): en claro, como la web.

Autenticación

  • Usuario anonymous (o ftp), con cualquier contraseña: ve los shares públicos.
  • Usuario y contraseña de [User …]: ve además los shares cuyo Users lo incluye.
  • Contraseñas fallidas: retardo creciente y límite de intentos por IP.

Comandos

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.
  • Los permisos del share se aplican igual que en la web: STOR sobre un fichero existente necesita Overwrite, DELE necesita Delete, etc. Las subidas también van a un temporal y se renombran al terminar.
  • Los directorios virtuales de las locations aparecen en LIST como carpetas.

Juego de caracteres de los nombres

  • Si el cliente activa OPTS UTF8 ON (o usa MLSD), UTF-8.
  • Si la sesión tiene perfil (ver abajo): dos → CP437 (o CP850), win16 → Windows-1252, mac → MacRoman.
  • Si no, el juego configurado en FtpCharset: iso-8859-1 (por defecto), macroman, cp437, cp850 o windows-1252.

Nombres cortos y Mac en FTP

FTP no dice qué cliente se conecta, así que los perfiles de CLIENTES.md se eligen por sesión:

  • Sufijo en el usuario: 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.
  • Comando SITE: SITE PROFILE dos|win16|mac|none, para clientes que permiten enviar comandos.
  • Por defecto (sin perfil): nombres reales y ficheros tal cual.
  • Subidas: un STOR con MacBinary II/III o BinHex válidos se decodifica siempre, como en la web (salvo Mac = false). Ver MAC-CLASICO.md.
  • Perfil 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).

WebDAV

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).

Alcance

  • Clase 1: 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.
  • Propiedades: displayname, resourcetype, getcontentlength, getcontenttype, getlastmodified, creationdate, getetag.
  • Cabeceras: DAV: 1, 2 y MS-Author-Via: DAV (la piden las "Carpetas web" de Windows 98/2000).
  • XML: se lee con XmlReader con DtdProcessing.Prohibit (sin entidades externas).
  • Permisos: los mismos del share; 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.
  • La raíz y las carpetas intermedias de locations son colecciones virtuales de solo lectura.
  • 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).
  • Probado con el redirector WebDAV de Windows (\\equipo@puerto\DavWWWRoot): listar, leer, copiar un fichero (PUT vacío, LOCK, PUT, PROPPATCH, UNLOCK), crear carpeta y renombrar.

Clientes y limitaciones conocidas

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)

De Sunfish a Sunfish

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.

  • Cliente WebDAV en 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).
  • Descubrimiento en la LAN con DNS-SD sobre mDNS: cada Sunfish se anuncia como _http._tcp, _webdav._tcp y _ftp._tcp, con un registro TXT sunfish=3 y path=/.
    • Las aplicaciones Sunfish listan los servidores de la red sin escribir IPs.
    • Los gestores de ficheros que exploran DNS-SD (GVfs, por ejemplo) los ven solos.
    • El Explorador de Windows no explora DNS-SD: ahí hay que escribir la dirección.
  • mDNS propio (UDP 5353 multicast, con 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).

  • El anunciante se llama <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.
  • La búsqueda pregunta desde un puerto cualquiera (los respondedores contestan a ese puerto, "legacy unicast"), así que funciona aunque el 5353 esté ocupado.
  • Probado en Windows: convive con el mDNS del sistema y un Sunfish se encuentra a sí mismo. Pendiente: comprobarlo con Avahi (Linux) y Bonjour (macOS).
  • sunfish-cli publicado con AOT pasa de ~4 MB a ~8 MB al incluir HttpClient y XML (cliente WebDAV).