Pro 에디션
Webview — 심층 참조
한눈에 보기
섹션 제목: “한눈에 보기”이 페이지는 공개 NextPDF\Pro\Webview 표면, 바이트 범위 요청/응답 모델, 그리고 공개 랜딩 페이지를 넘어서는 정확한 실패 모드를 문서화합니다.
가용성 및 라이선싱
섹션 제목: “가용성 및 라이선싱”이 기능은 NextPDF Pro(nextpdf/pro)에 포함되어 있으며 Pro 등급 라이선스 봉투로 활성화됩니다. 그 자격이 없는 배포는 이 기능의 클래스를 로드하지 않습니다. 에디션 비교 및 라이선스 받기.
기능별 라이선스 플래그는 없습니다. 코드는 Pro 에디션과 함께 배포됩니다. PSR-17 ResponseFactoryInterface / StreamFactoryInterface와 본문 미디어 타입은 라이선싱 제어가 아니라 런타임 생성자 매개변수입니다.
공개 API 표면
섹션 제목: “공개 API 표면”composer require nextpdf/proNextPDF\Pro\Webview 아래의 공개 타입:
LinearizedDocument— 전달을 위해 준비된 검증된 선형화 PDF.ByteRangeResponder— RFC 9110 바이트 범위 HTTP responder.ByteRange— 표현 위에서의 충족 가능한 포함 바이트 범위 하나.FirstPageProber— 구조적 “전체 다운로드 전 첫 페이지” 증명.
NextPDF\Pro\Webview\Exception 아래의 예외 타입:
WebviewException(마커 인터페이스),UnsupportedDocumentException,RangeNotSatisfiableException.
LinearizedDocument
섹션 제목: “LinearizedDocument”private 생성자를 가진 final readonly 클래스입니다. 명명된 생성자를 통해 인스턴스화하십시오.
static fromBytes(string $bytes): self— Core의 읽기 측LinearizationView::fromPdf()를 통해 바이트를 파싱합니다. 문서가 선형화되지 않았을 때, 선언된/L이 실제 바이트 길이와 일치하지 않을 때, 또는/E첫 페이지 끝 오프셋이 파일 내부의 양수 오프셋이 아닐 때UnsupportedDocumentException을 던집니다.length(): int— 바이트 단위 문서 길이.firstPagePrefixLength(): int— 완전한 첫 페이지를 담는 최소 선행 접두사. 파일 길이로 클램핑된/E오프셋입니다.firstPageByteRange(): ByteRange— 첫 페이지를 전달하는 포함 범위[0, /E - 1]. 접두사가 비어 있는 경우에만RangeNotSatisfiableException을 던집니다(심층 방어.fromBytes()가 이미0 < /E <= length를 보장합니다).slice(int $firstByte, int $lastByte): string— 포함 오프셋을 사용하는 엄격한 프로그래밍적 슬라이스. 범위를 벗어나면RangeNotSatisfiableException을 던집니다.etag(): string— 바이트에 대한 강하고 결정적인 SHA-256 엔티티 태그. 생성 시 한 번 메모이즈됩니다.
공개 readonly 속성: bytes(원시 PDF 바이트)와 view(Core LinearizationView).
ByteRangeResponder
섹션 제목: “ByteRangeResponder”PSR-7 / PSR-17에 대해서만 구현된 final readonly 클래스입니다.
__construct(ResponseFactoryInterface $responses, StreamFactoryInterface $streams, string $contentType = 'application/pdf')—$contentType이 제어 문자를 포함할 때InvalidArgumentException을 던집니다(이는 응답 및 멀티파트 파트 헤더에 보간됩니다. CR/LF 및 기타 제어 바이트는 헤더 주입을 방지하기 위해 거부됩니다).respond(LinearizedDocument $document, ServerRequestInterface $request): ResponseInterface— 문서 자신의ETag를 사용하여 선형화 문서에 대한 범위 요청에 답합니다.respondToBytes(string $bytes, ServerRequestInterface $request, ?string $etag = null): ResponseInterface— 임의의 바이트(선형화되지 않은 채로 범위를 지원해야 하는 표현)에 대한 범위 요청에 답합니다.etag가null일 때ETag는 바이트에서 도출됩니다.firstPageResponse(LinearizedDocument $document): ResponseInterface— 정확히 첫 페이지의 바이트 범위를 담은206을 빌드합니다. “전체 다운로드 전 첫 페이지”의 서버 푸시 형식입니다.
ByteRange
섹션 제목: “ByteRange”단일 충족 가능한 포함 바이트 범위(RFC 9110 §14.1.2)를 위한 final readonly 값 객체입니다.
__construct(int $firstByte, int $lastByte, int $contentLength)— 충족 가능성0 <= firstByte <= lastByte <= contentLength - 1을 강제합니다. 그렇지 않으면RangeNotSatisfiableException을 던집니다.length(): int— 포함 범위(lastByte - firstByte + 1). 항상>= 1입니다.contentRange(): string— RFC 9110 §14.4Content-Range필드 값bytes first-last/length.
공개 readonly 속성: firstByte, lastByte, contentLength.
FirstPageProber
섹션 제목: “FirstPageProber”LinearizedDocument로부터 생성되는 final readonly 클래스입니다.
prefixLength(): int— 첫 페이지를 렌더링하는 데 필요한 최소 선행 바이트 수.prefixFraction(): float— 접두사가 차지하는 전체 파일의 비율(0.0–1.0). 길이가 0인 파일에 대해서는1.0을 반환합니다.hintStreamWithinPrefix(): bool— 기본 힌트 스트림 객체가 첫 페이지 접두사 안에 완전히 들어 있는지(따라서 접두사만으로 리더가 1페이지 객체를 찾을 수 있는지). 힌트 스트림은 양의 길이를 가져야 합니다.isFirstPageSelfContained(): bool— 결합된 구조적 증명: 파일 안에 들어가고 힌트 스트림을 완전히 담는 양의 접두사.
바이트 범위 요청/응답 모델
섹션 제목: “바이트 범위 요청/응답 모델”ByteRangeResponder는 RFC 9110 §14를 따릅니다. 길이와 강한 SHA-256 ETag를 계산한 후, Range와 If-Range 헤더를 읽고 결정합니다.
| 조건 | 상태 | 비고 |
|---|---|---|
적용 가능한 Range가 없거나, If-Range가 현재의 강한 ETag와 일치하지 않음 | 200 OK | 전체 본문. If-Range의 강한 엔티티 태그 형식만 존중됩니다(RFC 9110 §13.1.5). |
인식되지 않는 범위 단위 또는 구문적으로 유효하지 않은 Range | 200 OK | 헤더가 무시됩니다(RFC 9110 §14.2). |
| 충족 가능한 범위 하나 | 206 Partial Content | Content-Range를 담습니다. |
| 충족 가능한 범위 여러 개 | 206 Partial Content | 도출된 경계를 가진 multipart/byteranges. |
| 유효한 바이트 범위, 충족 가능한 것 없음 | 416 Range Not Satisfiable | Content-Range: bytes */length를 담습니다(RFC 9110 §15.3.7). |
모든 응답은 Accept-Ranges: bytes와 강한 ETag를 광고합니다. 200과 206 응답은 Content-Type과 Content-Length도 설정합니다.
범위 파싱은 bytes= 단위만 받아들입니다. 명시적 first-last, 개방형 first-(끝으로 클램핑됨), 그리고 접미사 -N(최종 N바이트. 표현만큼 큰 접미사는 그 전체를 선택함)을 지원합니다. 단독 -(또는 그 외 잘못된 어떤 스펙이든)는 전체 Range 헤더를 구문적으로 유효하지 않게 만들므로, 헤더가 무시되고 전체 200 OK 표현이 반환됩니다. -0 접미사, 또는 첫 오프셋이 끝에 있거나 그것을 넘는 어떤 스펙이든 충족 불가능한 스펙이며 폐기됩니다. 헤더 내의 어떤 스펙도 충족 가능하지 않으면 응답은 416 Range Not Satisfiable입니다. 큰 십진 오프셋은 정수 오버플로 포화에 의존하지 않고 비교되므로, 30자리 Range 값이 플랫폼 독립적으로 처리됩니다. 겹치는 충족 가능한 범위는 어떤 본문이 빌드되기 전에 병합됩니다. 진정으로 별개인(겹치지 않는) 범위는 별도의 멀티파트 파트로 보존됩니다.
실패 모드 및 예외 모델
섹션 제목: “실패 모드 및 예외 모델”WebviewException은 Throwable을 확장하는 마커 인터페이스입니다. 이를 catch하여 전체 서브시스템을 일관되게 처리하십시오. 두 구체 예외 모두 이를 구현합니다.
UnsupportedDocumentException(InvalidArgumentException을 확장) — 바이트가 사용 가능한 선형화 문서가 아닐 때LinearizedDocument::fromBytes()에 의해 발생합니다. 명명된 생성자:notLinearized()(/Linearized매개변수 딕셔너리 없음),lengthMismatch($declaredLength, $actualLength)(선언된/L이 실제 길이와 일치하지 않음 — 잘림,/L을 넘는 증분 업데이트를 통한 추가, 또는 비적합), 그리고malformedFirstPageOffset($firstPageEndOffset, $length)(/E오프셋이 파일 내부의 양수 오프셋이 아님).RangeNotSatisfiableException(OutOfRangeException을 확장) — 프로그래밍적 슬라이스 오류. 포함 범위가 문서 밖으로 벗어날 때ByteRange::__construct()와LinearizedDocument::slice()/firstPageByteRange()에 의해 발생합니다. 명명된 생성자:outOfBounds($firstByte, $lastByte, $length).
HTTP responder는 클라이언트 Range 헤더에 대해 RangeNotSatisfiableException을 던지지 않습니다 — 충족 불가능한 HTTP 범위는 예외가 아니라 416 응답입니다(RFC 9110 §15.3.7). 그 예외는 범위를 벗어난 요청이 호출자 오류인 직접 프로그래밍적 슬라이싱을 위해 예약되어 있습니다. 구성된 contentType이 제어 문자를 포함할 때 ByteRangeResponder::__construct()는 (WebviewException이 아니라) 평범한 InvalidArgumentException을 던집니다.
서비스 거부 강화
섹션 제목: “서비스 거부 강화”responder는 요청당 존중하는 별개의 병합된 범위 수를 제한합니다(멀티파트 범위 증폭 부류, Apache HTTPD CVE-2011-3192). 요청이 병합된 범위의 상한보다 더 많이 요청하거나, 전체 표현보다 더 많은 총 바이트를 요청할 때, Range가 무시되고 전체 200이 반환됩니다. 멀티파트 경계는 결정적으로 도출되며 본문 내부에 절대 나타나지 않도록 보장될 때까지 다시 도출되므로, 재현 가능한 출력을 보존하면서 경계 충돌을 배제합니다.
적합성
섹션 제목: “적합성”바이트 범위 동작은 RFC 9110(HTTP Semantics)을 따릅니다. §14(범위 요청), §13.1.5(If-Range), §14.4(Content-Range), 그리고 §15.3.7(416). 선형화된 문서 레이아웃은 ISO 32000-2 Annex F의 Fast Web View 모델입니다. 이 모듈은 자신의 테스트로 검증된 동작을 넘어서는 추가 외부 조항 식별자를 주장하지 않습니다.
엣지 케이스 및 FIPS 모드 동작
섹션 제목: “엣지 케이스 및 FIPS 모드 동작”respondToBytes()는 첫 페이지 시맨틱이 필요하지 않을 때 임의의 바이트에 대해 범위를 제공합니다.If-RangeHTTP 날짜 검증자는 비일치로 취급됩니다 → 전체200(클라이언트는 단순히 다시 페치합니다).ETag는 순수하게 강한 캐시 검증자로 사용되는 SHA-256 해시입니다. 이 모듈은 서명이나 기타 암호 연산을 수행하지 않으며 FIPS 특화 동작을 정의하지 않습니다.
발행 경계
섹션 제목: “발행 경계”이 페이지는 외부에서 관찰 가능한 동작과 지원되는 공개 API 표면만 문서화합니다. 내부 네임스페이스 경로, 헬퍼 클래스, 메커니즘 표, 런북 파일명, 그리고 티켓 접두사는 범위 밖입니다.