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