--- name: dav_get_resource kind: function lang: py domain: infra version: "1.0.0" purity: impure signature: "def dav_get_resource(base_url: str, username: str, password: str, resource_path: str, *, timeout_s: float = 20.0, verify_tls: bool = True) -> dict" description: "Descarga (HTTP GET) el contenido de un recurso DAV individual (un VCARD o un VCALENDAR) con HTTP Basic auth. Construye el header Authorization: Basic base64(user:pass) a mano con stdlib. El resource_path puede ser un href absoluto (como los que devuelve dav_list_resources) o una URL completa. verify_tls=True por defecto. Maneja errores sin lanzar. Solo stdlib (urllib, base64, ssl). Probado contra Xandikos." tags: [dav, carddav, caldav, get, download, http, infra] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: [base64, ssl, urllib.error, urllib.request] params: - name: base_url desc: "URL base del servidor DAV. Se ignora si resource_path ya es una URL absoluta." - name: username desc: "usuario para HTTP Basic auth (p.ej. 'enmanuel')." - name: password desc: "contrasena para HTTP Basic auth. Resolver desde pass con pass_get_secret, nunca hardcodear." - name: resource_path desc: "href absoluto (p.ej. '/enmanuel/contacts/addressbook/x.vcf') o URL completa del recurso a descargar. Acepta directamente los hrefs que devuelve dav_list_resources." - name: timeout_s desc: "timeout de la peticion HTTP en segundos. Default 20.0." - name: verify_tls desc: "si True (default) verifica el certificado TLS. No desactivar salvo entorno de prueba." output: "dict. En exito: {status:'ok', http_status:int, text:str, url:str} donde text es el cuerpo del recurso (VCARD o VCALENDAR). En error (sin lanzar): {status:'error', error:str, http_status:int|None}." tested: true tests: - "test_construye_request_get_con_auth" - "test_resource_path_relativo_se_resuelve_con_base_url" - "test_resource_path_absoluto_se_respeta" - "test_devuelve_texto_del_recurso" - "test_httperror_devuelve_status_error" test_file_path: "python/functions/infra/dav_get_resource_test.py" file_path: "python/functions/infra/dav_get_resource.py" --- ## Ejemplo ```python import sys sys.path.insert(0, "python/functions") from infra.pass_get_secret import pass_get_secret from infra.dav_list_resources import dav_list_resources from infra.dav_get_resource import dav_get_resource base = "https://dav-eedeb681c4ab89ab8e444ac9.organic-machine.com" pw = pass_get_secret("dav/xandikos-enmanuel")["value"] # NO logear listing = dav_list_resources(base, "enmanuel", pw, "/enmanuel/contacts/addressbook/") first = listing["resources"][0]["href"] res = dav_get_resource(base, "enmanuel", pw, first) print(res["text"][:13]) # BEGIN:VCARD ``` ## Cuando usarla Cuando quieres leer el contenido de un recurso concreto cuyo href ya conoces (por `dav_list_resources` o porque lo construyes tu). Util para hacer backup de una coleccion (listar + get cada uno), validar que un import quedo bien escrito, o comparar etags en un sync. Acepta directamente los hrefs del listing sin reconstruir la URL. ## Gotchas - Lectura remota real sobre TLS; password de `pass`, no se logea. - Decodifica el cuerpo como UTF-8 con `errors='replace'`: bytes invalidos se sustituyen por el caracter de reemplazo en vez de fallar. - Si resource_path es relativo se concatena a base_url; si es absoluto (http/https) se usa tal cual y base_url se ignora. - `verify_tls=False` solo en pruebas; abre MITM.