Ir al contenido
getnextpdf.com

Pro edición

Webview — Referencia detallada

Esta página documenta la superficie pública NextPDF\Pro\Webview, el modelo de solicitud/respuesta por rango de bytes y los modos de fallo exactos, más allá de la página de presentación pública.

Esta capacidad se distribuye en NextPDF Pro (nextpdf/pro) y se activa con un sobre de licencia de nivel Pro. Un despliegue sin ese derecho no carga las clases de la capacidad. Compare ediciones y obtenga una licencia.

No existe ningún indicador de licencia por característica; el código se distribuye con la edición Pro. El ResponseFactoryInterface / StreamFactoryInterface de PSR-17 y el tipo de medio del cuerpo son parámetros de constructor en tiempo de ejecución, no controles de licenciamiento.

Ventana de terminal
composer require nextpdf/pro

Tipos públicos bajo NextPDF\Pro\Webview:

  • LinearizedDocument — un PDF linealizado validado y preparado para la entrega.
  • ByteRangeResponder — el responder HTTP por rango de bytes RFC 9110.
  • ByteRange — un rango de bytes inclusivo satisfacible sobre una representación.
  • FirstPageProber — la prueba estructural de «la primera página antes de la descarga completa».

Tipos de excepción bajo NextPDF\Pro\Webview\Exception:

  • WebviewException (interfaz marcadora), UnsupportedDocumentException, RangeNotSatisfiableException.

Una clase final readonly con un constructor privado; se instancia mediante el constructor con nombre.

  • static fromBytes(string $bytes): self — analiza los bytes a través del LinearizationView::fromPdf() del lado de lectura de Core. Lanza UnsupportedDocumentException cuando el documento no está linealizado, cuando el /L declarado no coincide con la longitud real en bytes, o cuando el desplazamiento /E de fin de primera página no es un desplazamiento positivo dentro del archivo.
  • length(): int — la longitud del documento en bytes.
  • firstPagePrefixLength(): int — el prefijo inicial mínimo que contiene la primera página completa: el desplazamiento /E, recortado a la longitud del archivo.
  • firstPageByteRange(): ByteRange — el rango inclusivo [0, /E - 1] que entrega la primera página. Lanza RangeNotSatisfiableException solo si el prefijo está vacío (defensa en profundidad; fromBytes() ya garantiza 0 < /E <= length).
  • slice(int $firstByte, int $lastByte): string — corte programático estricto con desplazamientos inclusivos; lanza RangeNotSatisfiableException cuando está fuera de límites.
  • etag(): string — la etiqueta de entidad SHA-256 fuerte y determinista para los bytes, memoizada una sola vez en la construcción.

Propiedades públicas de solo lectura: bytes (los bytes en bruto del PDF) y view (el LinearizationView de Core).

Una clase final readonly implementada únicamente contra PSR-7 / PSR-17.

  • __construct(ResponseFactoryInterface $responses, StreamFactoryInterface $streams, string $contentType = 'application/pdf') — lanza InvalidArgumentException cuando $contentType contiene caracteres de control (se interpola en las cabeceras de respuesta y de las partes multipart; CR/LF y otros bytes de control se rechazan para impedir la inyección de cabeceras).
  • respond(LinearizedDocument $document, ServerRequestInterface $request): ResponseInterface — responde a una solicitud de rango para un documento linealizado, usando el propio ETag del documento.
  • respondToBytes(string $bytes, ServerRequestInterface $request, ?string $etag = null): ResponseInterface — responde a una solicitud de rango para bytes arbitrarios (una representación que debe admitir rangos sin estar linealizada). El ETag se deriva de los bytes cuando es null.
  • firstPageResponse(LinearizedDocument $document): ResponseInterface — construye un 206 que transporta exactamente el rango de bytes de la primera página; la forma de envío por servidor de «la primera página antes de la descarga completa».

Un objeto de valor final readonly para un único rango de bytes inclusivo satisfacible (RFC 9110 §14.1.2).

  • __construct(int $firstByte, int $lastByte, int $contentLength) — impone la satisfacibilidad 0 <= firstByte <= lastByte <= contentLength - 1; lanza RangeNotSatisfiableException en caso contrario.
  • length(): int — el tramo inclusivo (lastByte - firstByte + 1), siempre >= 1.
  • contentRange(): string — el valor del campo Content-Range de RFC 9110 §14.4 bytes first-last/length.

Propiedades públicas de solo lectura: firstByte, lastByte, contentLength.

Una clase final readonly construida a partir de un LinearizedDocument.

  • prefixLength(): int — recuento mínimo de bytes iniciales necesario para renderizar la primera página.
  • prefixFraction(): float — fracción de todo el archivo (0.0–1.0) que representa el prefijo; devuelve 1.0 para un archivo de longitud cero.
  • hintStreamWithinPrefix(): bool — si el objeto de flujo de pistas primario se encuentra por completo dentro del prefijo de la primera página (de modo que el prefijo por sí solo permite a un lector localizar los objetos de la página 1). El flujo de pistas debe tener longitud positiva.
  • isFirstPageSelfContained(): bool — la prueba estructural combinada: un prefijo positivo que cabe dentro del archivo y contiene por completo el flujo de pistas.

Modelo de solicitud/respuesta por rango de bytes

Sección titulada «Modelo de solicitud/respuesta por rango de bytes»

ByteRangeResponder sigue RFC 9110 §14. Tras calcular la longitud y un ETag SHA-256 fuerte, lee las cabeceras Range e If-Range y decide:

CondiciónEstadoNotas
Sin Range aplicable, o If-Range no coincide con el ETag fuerte actual200 OKCuerpo completo. Solo se respeta la forma de etiqueta de entidad fuerte de If-Range (RFC 9110 §13.1.5).
Unidad de rango no reconocida o Range sintácticamente no válido200 OKLa cabecera se ignora (RFC 9110 §14.2).
Un rango satisfacible206 Partial ContentTransporta Content-Range.
Varios rangos satisfacibles206 Partial Contentmultipart/byteranges con un límite derivado.
Rangos de bytes válidos, ninguno satisfacible416 Range Not SatisfiableTransporta Content-Range: bytes */length (RFC 9110 §15.3.7).

Toda respuesta anuncia Accept-Ranges: bytes y el ETag fuerte. Las respuestas 200 y 206 también establecen Content-Type y Content-Length.

El análisis de rangos acepta únicamente la unidad bytes=. Admite first-last explícito, first- abierto (recortado al final) y el sufijo -N (los N bytes finales; un sufijo al menos tan grande como la representación selecciona toda ella). Un - solitario (o cualquier otra especificación malformada) hace que toda la cabecera Range sea sintácticamente no válida, de modo que la cabecera se ignora y se devuelve la representación 200 OK completa. Un sufijo -0, o cualquier especificación cuyo primer desplazamiento esté en el final o más allá, es una especificación insatisfacible y se descarta; si ninguna especificación de la cabecera es satisfacible, la respuesta es 416 Range Not Satisfiable. Los desplazamientos decimales grandes se comparan sin depender de la saturación por desbordamiento de enteros, de modo que un valor Range de 30 dígitos se gestiona de forma independiente de la plataforma. Los rangos satisfacibles solapados se fusionan antes de construir ningún cuerpo; los rangos genuinamente distintos (no solapados) se conservan como partes multipart separadas.

WebviewException es una interfaz marcadora que extiende Throwable; captúrela para gestionar todo el subsistema de forma uniforme. Ambas excepciones concretas la implementan.

  • UnsupportedDocumentException (extiende InvalidArgumentException) — la lanza LinearizedDocument::fromBytes() cuando los bytes no son un documento linealizado utilizable. Constructores con nombre: notLinearized() (sin diccionario de parámetros /Linearized), lengthMismatch($declaredLength, $actualLength) (el /L declarado no coincide con la longitud real — truncado, anexado mediante una actualización incremental más allá de /L, o no conforme), y malformedFirstPageOffset($firstPageEndOffset, $length) (el desplazamiento /E no es un desplazamiento positivo dentro del archivo).
  • RangeNotSatisfiableException (extiende OutOfRangeException) — el error de corte programático, lanzado por ByteRange::__construct() y LinearizedDocument::slice() / firstPageByteRange() cuando un rango inclusivo cae fuera del documento. Constructor con nombre: outOfBounds($firstByte, $lastByte, $length).

El responder HTTP no lanza RangeNotSatisfiableException para las cabeceras Range del cliente: un rango HTTP insatisfacible es una respuesta 416 (RFC 9110 §15.3.7), no una excepción. Esa excepción se reserva para el corte programático directo, donde una solicitud fuera de límites es un error del llamante. ByteRangeResponder::__construct() lanza una InvalidArgumentException simple (no una WebviewException) cuando el contentType configurado contiene caracteres de control.

Endurecimiento contra la denegación de servicio

Sección titulada «Endurecimiento contra la denegación de servicio»

El responder limita el número de rangos fusionados distintos que respeta por solicitud (la clase de amplificación de rango multipart, Apache HTTPD CVE-2011-3192). Cuando una solicitud pide más rangos fusionados que el límite, o más bytes totales que toda la representación, el Range se ignora y se devuelve un 200 completo. El límite multipart se deriva de forma determinista y se vuelve a derivar hasta que está garantizado que no aparece dentro del cuerpo, preservando una salida reproducible a la vez que se descarta la colisión de límites.

El comportamiento por rango de bytes sigue RFC 9110 (HTTP Semantics): §14 (solicitudes de rango), §13.1.5 (If-Range), §14.4 (Content-Range) y §15.3.7 (416). La disposición de documento linealizado es el modelo Fast Web View de ISO 32000-2 Annex F. El módulo no afirma más identificadores de cláusula externos que el comportamiento verificado por sus pruebas.

  • respondToBytes() sirve rangos sobre bytes arbitrarios cuando no se necesita la semántica de primera página.
  • Un validador If-Range de fecha HTTP se trata como una no coincidencia → 200 completo (el cliente simplemente vuelve a obtener el archivo).
  • El ETag es un hash SHA-256 usado puramente como validador de caché fuerte; este módulo no realiza ninguna firma ni otra operación criptográfica y no define ningún comportamiento específico de FIPS.

Esta página documenta únicamente el comportamiento observable externamente y la superficie de API pública admitida. Las rutas de espacio de nombres internas, las clases auxiliares, las tablas de mecanismos, los nombres de archivo de runbook y los prefijos de tickets quedan fuera de alcance.