Salta ai contenuti

Risoluzione dei problemi di Gotenberg in NextPDF

Il bridge fallisce in modo esplicito e tempestivo. Ogni fallimento è un’eccezione tipizzata e il relativo messaggio ne indica la causa. Questa pagina ne è il catalogo. Per ciascun fallimento fornisce il tipo di eccezione, il frammento di messaggio visibile, il trigger esatto nel percorso del codice e la correzione.

Le famiglie di eccezioni sono:

  • GotenbergConvertException — fallimento a livello di conversione (configurazione, trasporto o risposta).
  • RuntimeException — fallimento a livello di validazione sollevato dal criterio di sicurezza, prima di qualsiasi traffico di rete.
  • ValueError — un’estensione di file non riconosciuta.
  • InvalidSpkiPinException — una stringa di pin TLS malformata.

”Invalid Gotenberg configuration: apiUrl is empty”

Sezione intitolata “”Invalid Gotenberg configuration: apiUrl is empty””
  • Tipo: GotenbergConvertException
  • Trigger: convertFile() o convertString() è stato chiamato mentre GotenbergConfig::isValid() è false. Questo avviene quando apiUrl è una stringa vuota.
  • Correzione: fornire un URL HTTPS non vuoto. Se si costruisce la configurazione con fromArray(), tenere presente che assegna silenziosamente '' a un api_url mancante o non stringa. Validare l’origine della configurazione nel percorso di avvio.

Provengono dal criterio di sicurezza, che protegge dal Server-Side Request Forgery (SSRF). Vengono sollevati prima dell’invio di qualsiasi richiesta. Sono semplici RuntimeException.

”Gotenberg API URL must use HTTPS (got: http)”

Sezione intitolata “”Gotenberg API URL must use HTTPS (got: http)””
  • Trigger: lo schema dell’URL configurato non è https. Il controllo non distingue tra maiuscole e minuscole, quindi HTTPS:// è accettato.
  • Correzione: terminare TLS davanti a Gotenberg e configurare l’endpoint HTTPS. L’HTTP in chiaro viene rifiutato anche per lo sviluppo locale.
  • Trigger: l’URL non può essere scomposto in uno schema e un host.
  • Correzione: fornire un URL assoluto sintatticamente valido, per esempio https://gotenberg.example.com:3000.

”Gotenberg API URL must not resolve to a private or reserved IP address”

Sezione intitolata “”Gotenberg API URL must not resolve to a private or reserved IP address””
  • Trigger: l’host è un IP letterale privato o riservato, oppure un nome host che si risolve (tramite tutti i record A/AAAA) in almeno un indirizzo privato o riservato. Questo blocca gli intervalli RFC 1918, loopback e link-local.
  • Correzione: puntare il bridge a un indirizzo di servizio pubblico instradabile o adeguatamente segmentato. Se Gotenberg si trova intenzionalmente su una rete privata, la protezione SSRF del bridge lo rifiuta per progettazione. Esporlo tramite un indirizzo accettato dalla protezione, quindi proteggere quel percorso con controlli di rete e autenticazione. Vedere /integrations/gotenberg/security-and-operations/.

”Gotenberg API URL DNS answer changed since validation — possible DNS rebinding attack”

Sezione intitolata “”Gotenberg API URL DNS answer changed since validation — possible DNS rebinding attack””
  • Trigger: tra la validazione iniziale e la richiesta, una nuova risoluzione DNS ha restituito un indirizzo che non era nell’insieme validato in origine.
  • Correzione: è la protezione time-of-check/time-of-use che interviene. Esaminare il DNS dell’host. Una causa legittima è un bilanciatore di carico che ruota gli indirizzi. Una causa dannosa è un attacco di rebinding. Usare un indirizzo stabile o un nome con un insieme di record stabile per l’endpoint Gotenberg.

Vengono sollevati dal criterio di sicurezza prima della richiesta. Ciascuno è una semplice RuntimeException, salvo dove indicato.

  • Tipo: GotenbergConvertException
  • Trigger: convertFile() non è riuscito a risolvere il percorso in forma canonica, oppure il percorso risolto non è un file regolare leggibile. Anche una directory provoca questo errore.
  • Correzione: passare il percorso di un file esistente e leggibile. Il percorso viene prima risolto in forma canonica con realpath(), neutralizzando anche il traversal.

”File size ( bytes) exceeds maximum allowed size ( bytes)”

Sezione intitolata “”File size ( bytes) exceeds maximum allowed size ( bytes)””
  • Trigger: l’input è più grande di maxFileSize (predefinito 52.428.800 byte = 50 MiB).
  • Correzione: aumentare maxFileSize se il documento lo richiede legittimamente, oppure rifiutare il caricamento a monte. Mantenere il limite più basso possibile, compatibilmente con i documenti reali. È l’unico limite di risorse integrato del bridge.

Il nome del file viene controllato. Per le conversioni da file, il nome del file è il basename del percorso risolto; per convertString() è il nome passato. Ciascuno di questi casi è un RuntimeException:

Frammento di messaggioTrigger
must not be emptynome file vuoto
path traversal sequences (..)il nome contiene ..
forward slashesil nome contiene /
backslashesil nome contiene \
null bytesil nome contiene un byte NUL
control charactersil nome contiene un carattere di controllo ASCII (0–31)
  • Correzione: passare un basename pulito. Per convertString() fornire un nome semplice come report.docx. Viene usato per rilevare il formato e come nome del file nel caricamento multipart, non come percorso.
  • Tipo: ValueError
  • Trigger: l’estensione del file non è una di docx, xlsx, pptx, odt, ods, odp (senza distinzione tra maiuscole e minuscole, con il punto iniziale tollerato).
  • Correzione: convertire solo i sei formati riconosciuti. Il bridge non riconosce i formati binari legacy (.doc, .xls, .ppt), .rtf, .csv, il testo semplice o le immagini. Convertire questi input in un formato riconosciuto prima di chiamare il bridge, oppure gestirli con un percorso diverso.

Tutti questi sono GotenbergConvertException.

  • Trigger: il client PSR-18 (o il trasporto con pinning cURL) ha sollevato un’eccezione durante l’invio della richiesta. La causa può essere un rifiuto di connessione, un timeout, un fallimento dell’handshake TLS o una mancata corrispondenza del pin.
  • Codice di eccezione: il codice dell’eccezione del client sottostante.
  • Causa: l’eccezione originale del client PSR-18 è allegata come eccezione precedente.
  • Correzione: controllare quattro aspetti. Verificare la raggiungibilità del servizio con isAvailable(). Verificare il percorso di rete. Verificare la catena TLS. Se è configurato il pinning, verificare che il SubjectPublicKeyInfo (SPKI) corrente del server corrisponda a un pin configurato. Una mancata corrispondenza del pin dopo una rotazione del certificato è la causa classica. Vedere la procedura di rotazione in /integrations/gotenberg/security-and-operations/.
  • Trigger: la chiamata curl_exec del trasporto con pinning cURL è fallita con un numero di errore cURL diverso da zero, oppure ha restituito un corpo non stringa.
  • Correzione: il numero di errore cURL identifica la causa (TLS, risoluzione, timeout, pin). Un fallimento del pinning si manifesta qui quando CURLOPT_PINNEDPUBLICKEY rifiuta il certificato. Confermare che i pin configurati e l’indirizzo risolto siano aggiornati.
  • Trigger: lo stato della risposta non era 200. Il corpo è incluso, troncato ai primi 500 caratteri, con puntini di sospensione aggiunti quando è più lungo.
  • Correzione: leggere il corpo incluso. Il messaggio di errore di Gotenberg spiega perché la conversione è stata rifiutata: contenuto del documento non supportato, un fallimento interno di LibreOffice o un rifiuto di autenticazione con un 401 o 403. Un 401/403 significa che apiKey è mancante o errato. Un 5xx è un fallimento lato servizio ed è un candidato per un nuovo tentativo limitato.

”Unexpected Content-Type from Gotenberg: (expected application/pdf)”

Sezione intitolata “”Unexpected Content-Type from Gotenberg: (expected application/pdf)””
  • Trigger: lo stato era 200 ma il Content-Type della risposta non conteneva application/pdf.
  • Correzione: di solito significa che un proxy o un gateway ha restituito una pagina di errore HTML o di reindirizzamento con un 200. Il bridge disabilita deliberatamente il seguito dei reindirizzamenti sul trasporto con pinning, in modo che un 3xx non venga seguito silenziosamente verso un host non verificato. Un corpo che arriva con il tipo errato segnala che qualcosa tra l’applicazione e Gotenberg sta interferendo. Esaminare il percorso di rete.

”Response body does not start with %PDF header — invalid PDF data”

Sezione intitolata “”Response body does not start with %PDF header — invalid PDF data””
  • Trigger: stato 200, Content-Type accettabile, ma il corpo non inizia con la firma %PDF.
  • Correzione: l’upstream ha restituito qualcosa che non è un PDF, nonostante le intestazioni. Trattare la risposta come non attendibile ed esaminare il servizio. Non scrivere il corpo su disco. Il bridge si rifiuta di restituirlo come risultato.
  • Tipo: InvalidSpkiPinException
  • Trigger: una stringa di pin configurata non inizia con sha256/ o sha256//.
  • Correzione: formattare ciascun pin come sha256/<base64-encoded-spki-hash>. Il trasporto accetta anche la forma nativa di cURL sha256//<base64>. Generare il valore dal SubjectPublicKeyInfo del certificato del server, non dall’intero certificato.

isAvailable() restituisce false senza alcuna chiamata di rete quando l’URL è vuoto, non è HTTPS o si risolve in un indirizzo private/reserved. Restituisce false anche in caso di qualsiasi errore di rete, oppure quando /health restituisce 500 o superiore; in questi casi intercetta l’errore anziché sollevarlo. Verificare, in ordine:

  1. L’URL configurato è non vuoto e HTTPS.
  2. L’host non si risolve in un indirizzo private/reserved (la protezione SSRF lo rifiuta anche per la sonda).
  3. <apiUrl>/health è raggiungibile dall’host dell’applicazione e restituisce uno stato inferiore a 500.
  • /integrations/gotenberg/configuration/ — ogni opzione e le regole di selezione del trasporto.
  • /integrations/gotenberg/production-usage/ — il criterio di nuovo tentativo e il contratto di gestione dei fallimenti.
  • /integrations/gotenberg/security-and-operations/ — il modello SSRF e la rotazione dei pin.
  • /integrations/gotenberg/quickstart/ — l’ordine esaustivo di cattura nel contesto.