Pular para o conteúdo
getnextpdf.com

Pro edição

Webview — Referência Profunda

Esta página documenta a superfície pública NextPDF\Pro\Webview, o modelo de requisição/resposta por intervalo de bytes e os exatos modos de falha além da página pública de apresentação.

Esta capacidade é distribuída no NextPDF Pro (nextpdf/pro) e é ativada com um envelope de licença de nível Pro. Uma implantação sem essa titularidade não carrega as classes da capacidade. Compare as edições e obtenha uma licença.

Não há sinalizador de licença por recurso; o código é distribuído com a edição Pro. O ResponseFactoryInterface / StreamFactoryInterface PSR-17 e o media type do corpo são parâmetros de runtime do construtor, não controles de licenciamento.

Terminal window
composer require nextpdf/pro

Tipos públicos sob NextPDF\Pro\Webview:

  • LinearizedDocument — um PDF linearizado validado e preparado para a entrega.
  • ByteRangeResponder — o responder HTTP por intervalo de bytes do RFC 9110.
  • ByteRange — um intervalo de bytes inclusivo satisfazível sobre uma representação.
  • FirstPageProber — a prova estrutural de “primeira página antes do download completo”.

Tipos de exceção sob NextPDF\Pro\Webview\Exception:

  • WebviewException (interface marcadora), UnsupportedDocumentException, RangeNotSatisfiableException.

Uma classe final readonly com um construtor privado; instancie via o construtor nomeado.

  • static fromBytes(string $bytes): self — analisa os bytes por meio da LinearizationView::fromPdf() do lado de leitura do Core. Lança UnsupportedDocumentException quando o documento não é linearizado, quando o /L declarado não corresponde ao comprimento real em bytes, ou quando o offset /E de fim da primeira página não é um offset positivo dentro do arquivo.
  • length(): int — o comprimento do documento em bytes.
  • firstPagePrefixLength(): int — o prefixo inicial mínimo que contém a primeira página completa: o offset /E, fixado ao comprimento do arquivo.
  • firstPageByteRange(): ByteRange — o intervalo inclusivo [0, /E - 1] que entrega a primeira página. Lança RangeNotSatisfiableException apenas se o prefixo for vazio (defesa em profundidade; fromBytes() já garante 0 < /E <= length).
  • slice(int $firstByte, int $lastByte): string — fatia programática estrita com offsets inclusivos; lança RangeNotSatisfiableException quando fora dos limites.
  • etag(): string — a entity-tag SHA-256 forte e determinística para os bytes, memoizada uma única vez na construção.

Propriedades públicas readonly: bytes (os bytes brutos do PDF) e view (a LinearizationView do Core).

Uma classe final readonly implementada apenas contra PSR-7 / PSR-17.

  • __construct(ResponseFactoryInterface $responses, StreamFactoryInterface $streams, string $contentType = 'application/pdf') — lança InvalidArgumentException quando $contentType contém caracteres de controle (ele é interpolado nos cabeçalhos da resposta e das partes multipart; CR/LF e outros bytes de controle são rejeitados para evitar injeção de cabeçalho).
  • respond(LinearizedDocument $document, ServerRequestInterface $request): ResponseInterface — responde a uma requisição de intervalo para um documento linearizado, usando o próprio ETag do documento.
  • respondToBytes(string $bytes, ServerRequestInterface $request, ?string $etag = null): ResponseInterface — responde a uma requisição de intervalo para bytes arbitrários (uma representação que deve suportar intervalos sem ser linearizada). O ETag é derivado dos bytes quando null.
  • firstPageResponse(LinearizedDocument $document): ResponseInterface — constrói um 206 carregando exatamente o intervalo de bytes da primeira página; a forma de server-push de “primeira página antes do download completo”.

Um value object final readonly para um único intervalo de bytes inclusivo satisfazível (RFC 9110 §14.1.2).

  • __construct(int $firstByte, int $lastByte, int $contentLength) — impõe a satisfazibilidade 0 <= firstByte <= lastByte <= contentLength - 1; lança RangeNotSatisfiableException caso contrário.
  • length(): int — o intervalo inclusivo (lastByte - firstByte + 1), sempre >= 1.
  • contentRange(): string — o valor do campo Content-Range do RFC 9110 §14.4 bytes first-last/length.

Propriedades públicas readonly: firstByte, lastByte, contentLength.

Uma classe final readonly construída a partir de um LinearizedDocument.

  • prefixLength(): int — a contagem mínima de bytes iniciais necessária para renderizar a primeira página.
  • prefixFraction(): float — a fração de todo o arquivo (0.0–1.0) que o prefixo representa; retorna 1.0 para um arquivo de comprimento zero.
  • hintStreamWithinPrefix(): bool — se o objeto de stream de hint primário está totalmente dentro do prefixo da primeira página (de modo que apenas o prefixo permita a um leitor localizar os objetos da página 1). O stream de hint deve ter comprimento positivo.
  • isFirstPageSelfContained(): bool — a prova estrutural combinada: um prefixo positivo que cabe dentro do arquivo e contém totalmente o stream de hint.

Modelo de requisição/resposta por intervalo de bytes

Seção intitulada “Modelo de requisição/resposta por intervalo de bytes”

ByteRangeResponder segue o RFC 9110 §14. Após calcular o comprimento e um ETag SHA-256 forte, ele lê os cabeçalhos Range e If-Range e decide:

CondiçãoStatusNotas
Sem Range aplicável, ou If-Range não corresponde ao ETag forte atual200 OKCorpo completo. Apenas a forma de entity-tag forte de If-Range é honrada (RFC 9110 §13.1.5).
Unidade de intervalo não reconhecida ou Range sintaticamente inválido200 OKO cabeçalho é ignorado (RFC 9110 §14.2).
Um intervalo satisfazível206 Partial ContentCarrega Content-Range.
Vários intervalos satisfazíveis206 Partial Contentmultipart/byteranges com um boundary derivado.
Intervalos de bytes válidos, nenhum satisfazível416 Range Not SatisfiableCarrega Content-Range: bytes */length (RFC 9110 §15.3.7).

Toda resposta anuncia Accept-Ranges: bytes e o ETag forte. As respostas 200 e 206 também definem Content-Type e Content-Length.

A análise de intervalo aceita apenas a unidade bytes=. Ela suporta first-last explícito, first- em aberto (fixado ao fim) e sufixo -N (os últimos N bytes; um sufixo pelo menos tão grande quanto a representação seleciona-a por inteiro). Um - isolado (ou qualquer outra spec malformada) torna todo o cabeçalho Range sintaticamente inválido, de modo que o cabeçalho é ignorado e a representação 200 OK completa é retornada. Um sufixo -0, ou qualquer spec cujo primeiro offset esteja no fim ou além dele, é uma spec insatisfazível e é descartada; se nenhuma spec do cabeçalho for satisfazível, a resposta é 416 Range Not Satisfiable. Offsets decimais grandes são comparados sem depender da saturação por estouro de inteiro (integer-overflow), de modo que um valor Range de 30 dígitos é tratado de forma independente de plataforma. Intervalos satisfazíveis sobrepostos são coalescidos antes que qualquer corpo seja construído; intervalos genuinamente distintos (não sobrepostos) são preservados como partes multipart separadas.

WebviewException é uma interface marcadora que estende Throwable; capture-a para tratar todo o subsistema de maneira uniforme. Ambas as exceções concretas a implementam.

  • UnsupportedDocumentException (estende InvalidArgumentException) — levantada por LinearizedDocument::fromBytes() quando os bytes não são um documento linearizado utilizável. Construtores nomeados: notLinearized() (sem dicionário de parâmetros /Linearized), lengthMismatch($declaredLength, $actualLength) (o /L declarado não corresponde ao comprimento real — truncado, com anexos via uma atualização incremental além de /L, ou não conforme) e malformedFirstPageOffset($firstPageEndOffset, $length) (o offset /E não é um offset positivo dentro do arquivo).
  • RangeNotSatisfiableException (estende OutOfRangeException) — o erro de fatiamento programático, levantado por ByteRange::__construct() e LinearizedDocument::slice() / firstPageByteRange() quando um intervalo inclusivo cai fora do documento. Construtor nomeado: outOfBounds($firstByte, $lastByte, $length).

O responder HTTP não lança RangeNotSatisfiableException para cabeçalhos Range do cliente — um intervalo HTTP insatisfazível é uma resposta 416 (RFC 9110 §15.3.7), não uma exceção. Essa exceção é reservada para o fatiamento programático direto, em que uma requisição fora dos limites é um erro do chamador. ByteRangeResponder::__construct() lança uma InvalidArgumentException simples (não uma WebviewException) quando o contentType configurado contém caracteres de controle.

O responder limita o número de intervalos coalescidos distintos honrados por requisição (a classe de amplificação de intervalo multipart, Apache HTTPD CVE-2011-3192). Quando uma requisição pede mais intervalos coalescidos do que o limite, ou mais bytes totais do que toda a representação, o Range é ignorado e um 200 completo é retornado. O boundary de multipart é derivado de forma determinística e re-derivado até ter a garantia de não ocorrer dentro do corpo, preservando a saída reproduzível ao mesmo tempo em que descarta a colisão de boundary.

O comportamento por intervalo de bytes segue o RFC 9110 (HTTP Semantics): §14 (requisições de intervalo), §13.1.5 (If-Range), §14.4 (Content-Range) e §15.3.7 (416). O layout de documento linearizado é o modelo Fast Web View do ISO 32000-2 Annex F. O módulo não afirma nenhum identificador de cláusula externo além do comportamento verificado por seus testes.

  • respondToBytes() serve intervalos sobre bytes arbitrários quando a semântica de primeira página não é necessária.
  • Um validador If-Range de data HTTP é tratado como não correspondente → 200 completo (o cliente simplesmente busca novamente).
  • O ETag é um hash SHA-256 usado puramente como um validador de cache forte; este módulo não realiza nenhuma assinatura ou outra operação criptográfica e não define nenhum comportamento específico de FIPS.

Esta página documenta apenas o comportamento observável externamente e a superfície pública da API suportada. Caminhos de namespace internos, classes auxiliares, tabelas de mecanismos, nomes de arquivos de runbook e prefixos de tíquete estão fora do escopo.