Pro รุ่น
Webview — การอ้างอิงเชิงลึก
ภาพรวมโดยสังเขป
หัวข้อที่มีชื่อว่า “ภาพรวมโดยสังเขป”หน้านี้บันทึกพื้นผิว NextPDF\Pro\Webview สาธารณะ แบบจำลองคำขอ/การตอบกลับแบบ byte-range และโหมดความล้มเหลวที่แน่ชัดที่เกินกว่าหน้าแลนดิ้งสาธารณะ
ความพร้อมใช้งานและการอนุญาตสิทธิ์
หัวข้อที่มีชื่อว่า “ความพร้อมใช้งานและการอนุญาตสิทธิ์”ความสามารถนี้มาพร้อมกับ NextPDF Pro (nextpdf/pro) และเปิดใช้งานด้วย license envelope ระดับ Pro การนำไปใช้งานที่ไม่มีสิทธิ์ดังกล่าวจะไม่โหลดคลาสของความสามารถนี้ เปรียบเทียบรุ่นและรับสิทธิ์การใช้งาน
ไม่มีแฟล็กสิทธิ์การใช้งานต่อฟีเจอร์ โค้ดมาพร้อมกับรุ่น Pro ส่วน PSR-17 ResponseFactoryInterface / StreamFactoryInterface และชนิดสื่อของเนื้อหาเป็นพารามิเตอร์ของ constructor ในขณะรัน ไม่ใช่กลไกควบคุมการอนุญาตสิทธิ์
พื้นผิว API สาธารณะ
หัวข้อที่มีชื่อว่า “พื้นผิว API สาธารณะ”composer require nextpdf/proชนิดสาธารณะภายใต้ NextPDF\Pro\Webview:
LinearizedDocument— PDF ที่ผ่าน linearized ซึ่งตรวจสอบแล้วและเตรียมพร้อมสำหรับการส่งมอบByteRangeResponder— ตัวตอบกลับ HTTP แบบ byte-range ตาม RFC 9110ByteRange— ช่วงไบต์แบบ inclusive ที่ตอบสนองได้หนึ่งช่วงเหนือการแทนเอกสารFirstPageProber— การพิสูจน์เชิงโครงสร้าง “หน้าแรกก่อนดาวน์โหลดเต็ม”
ชนิดข้อยกเว้นภายใต้ NextPDF\Pro\Webview\Exception:
WebviewException(marker interface),UnsupportedDocumentException,RangeNotSatisfiableException
LinearizedDocument
หัวข้อที่มีชื่อว่า “LinearizedDocument”คลาส final readonly ที่มี constructor แบบ private ให้สร้างอินสแตนซ์ผ่าน named constructor
static fromBytes(string $bytes): self— แจงไบต์ผ่านLinearizationView::fromPdf()ฝั่งอ่านของ Core ยกUnsupportedDocumentExceptionเมื่อเอกสารไม่ได้ linearized เมื่อ/Lที่ประกาศไว้ไม่ตรงกับความยาวไบต์จริง หรือเมื่อออฟเซ็ตจบหน้าแรก/Eไม่ใช่ออฟเซ็ตค่าบวกภายในไฟล์length(): int— ความยาวของเอกสารเป็นไบต์firstPagePrefixLength(): int— prefix ส่วนต้นน้อยที่สุดที่บรรจุหน้าแรกครบถ้วน นั่นคือออฟเซ็ต/Eที่ถูกจำกัดให้ไม่เกินความยาวไฟล์firstPageByteRange(): ByteRange— ช่วงแบบ inclusive[0, /E - 1]ที่ส่งมอบหน้าแรก ยกRangeNotSatisfiableExceptionเฉพาะเมื่อ prefix ว่างเปล่าเท่านั้น (defence-in-depth โดยfromBytes()รับประกัน0 < /E <= lengthไว้แล้ว)slice(int $firstByte, int $lastByte): string— การ slice เชิงโปรแกรมแบบเข้มงวดด้วยออฟเซ็ต inclusive ยกRangeNotSatisfiableExceptionเมื่ออยู่นอกขอบเขตetag(): string— strong SHA-256 entity-tag ที่กำหนดได้แน่นอนสำหรับไบต์ ถูก memoise ครั้งเดียวตอนสร้าง
คุณสมบัติสาธารณะแบบ readonly: bytes (ไบต์ PDF ดิบ) และ view (Core LinearizationView)
ByteRangeResponder
หัวข้อที่มีชื่อว่า “ByteRangeResponder”คลาส final readonly ที่อิมพลีเมนต์เทียบกับ PSR-7 / PSR-17 เท่านั้น
__construct(ResponseFactoryInterface $responses, StreamFactoryInterface $streams, string $contentType = 'application/pdf')— ยกInvalidArgumentExceptionเมื่อ$contentTypeมีอักขระควบคุม (เนื่องจากมันถูกแทรกเข้าไปในเฮดเดอร์ของการตอบกลับและของ multipart part จึงปฏิเสธ CR/LF และไบต์ควบคุมอื่น ๆ เพื่อป้องกัน header injection)respond(LinearizedDocument $document, ServerRequestInterface $request): ResponseInterface— ตอบคำขอช่วงสำหรับเอกสาร linearized โดยใช้ETagของเอกสารเองrespondToBytes(string $bytes, ServerRequestInterface $request, ?string $etag = null): ResponseInterface— ตอบคำขอช่วงสำหรับไบต์ใด ๆ (การแทนเอกสารที่ควรรองรับช่วงโดยไม่ต้องผ่าน linearized)ETagจะถูกอนุมานจากไบต์เมื่อเป็นnullfirstPageResponse(LinearizedDocument $document): ResponseInterface— สร้าง206ที่บรรจุช่วงไบต์ของหน้าแรกพอดี ซึ่งเป็นรูปแบบ server-push ของ “หน้าแรกก่อนดาวน์โหลดเต็ม”
ByteRange
หัวข้อที่มีชื่อว่า “ByteRange”ออบเจกต์ค่า final readonly สำหรับช่วงไบต์แบบ inclusive ที่ตอบสนองได้หนึ่งช่วง (RFC 9110 §14.1.2)
__construct(int $firstByte, int $lastByte, int $contentLength)— บังคับใช้ความสามารถในการตอบสนอง0 <= firstByte <= lastByte <= contentLength - 1มิฉะนั้นยกRangeNotSatisfiableExceptionlength(): int— ช่วงแบบ inclusive (lastByte - firstByte + 1) มีค่า>= 1เสมอcontentRange(): string— ค่าฟิลด์Content-Rangeตาม RFC 9110 §14.4 คือbytes first-last/length
คุณสมบัติสาธารณะแบบ readonly: firstByte, lastByte, contentLength
FirstPageProber
หัวข้อที่มีชื่อว่า “FirstPageProber”คลาส final readonly ที่สร้างจาก LinearizedDocument
prefixLength(): int— จำนวนไบต์ส่วนต้นน้อยที่สุดที่จำเป็นต่อการเรนเดอร์หน้าแรกprefixFraction(): float— สัดส่วนของไฟล์ทั้งไฟล์ (0.0–1.0) ที่ prefix แทน คืนค่า1.0สำหรับไฟล์ที่มีความยาวเป็นศูนย์hintStreamWithinPrefix(): bool— ว่าออบเจกต์ hint stream หลักอยู่ภายใน prefix ของหน้าแรกครบถ้วนหรือไม่ (เพื่อให้ prefix เพียงอย่างเดียวให้โปรแกรมอ่านระบุตำแหน่งออบเจกต์ของหน้าที่ 1 ได้) hint stream ต้องมีความยาวเป็นค่าบวกisFirstPageSelfContained(): bool— การพิสูจน์เชิงโครงสร้างแบบรวม นั่นคือ prefix ค่าบวกที่พอดีภายในไฟล์และบรรจุ hint stream ครบถ้วน
แบบจำลองคำขอ/การตอบกลับแบบ byte-range
หัวข้อที่มีชื่อว่า “แบบจำลองคำขอ/การตอบกลับแบบ byte-range”ByteRangeResponder เป็นไปตาม RFC 9110 §14 หลังจากคำนวณความยาวและ strong SHA-256 ETag แล้ว มันอ่านเฮดเดอร์ Range และ If-Range แล้วตัดสินใจดังนี้:
| Condition | Status | Notes |
|---|---|---|
ไม่มี Range ที่ใช้ได้ หรือ If-Range ไม่ตรงกับ strong ETag ปัจจุบัน | 200 OK | เนื้อหาเต็ม เฉพาะรูปแบบ strong entity-tag ของ If-Range เท่านั้นที่ได้รับการยอมรับ (RFC 9110 §13.1.5) |
หน่วยช่วงที่ไม่รู้จัก หรือ Range ที่ไม่ถูกต้องตามไวยากรณ์ | 200 OK | เฮดเดอร์ถูกเพิกเฉย (RFC 9110 §14.2) |
| ช่วงเดียวที่ตอบสนองได้ | 206 Partial Content | บรรจุ Content-Range |
| หลายช่วงที่ตอบสนองได้ | 206 Partial Content | multipart/byteranges พร้อม boundary ที่อนุมานขึ้น |
| ช่วงไบต์ที่ถูกต้อง แต่ไม่มีช่วงใดตอบสนองได้ | 416 Range Not Satisfiable | บรรจุ Content-Range: bytes */length (RFC 9110 §15.3.7) |
ทุกการตอบกลับจะประกาศ Accept-Ranges: bytes และ strong ETag การตอบกลับ 200 และ 206 ยังตั้งค่า Content-Type และ Content-Length ด้วย
การแจงช่วงรับเฉพาะหน่วย bytes= เท่านั้น มันรองรับ first-last แบบชัดเจน, first- แบบปลายเปิด (ถูกจำกัดให้สิ้นสุดที่ปลายไฟล์) และ suffix -N (N ไบต์สุดท้าย โดย suffix ที่ใหญ่อย่างน้อยเท่ากับการแทนเอกสารจะเลือกทั้งหมด) - เปล่า ๆ (หรือสเปกที่ผิดรูปแบบในลักษณะอื่น) ทำให้เฮดเดอร์ Range ทั้งหมดไม่ถูกต้องตามไวยากรณ์ เฮดเดอร์จึงถูกเพิกเฉยและคืนค่าการแทนเอกสารแบบ 200 OK เต็ม suffix -0 หรือสเปกใดที่ออฟเซ็ตแรกอยู่ที่ปลายไฟล์หรือเลยไป เป็นสเปกที่ตอบสนองไม่ได้และถูกทิ้ง หากไม่มีสเปกใดในเฮดเดอร์ที่ตอบสนองได้ การตอบกลับคือ 416 Range Not Satisfiable ออฟเซ็ตทศนิยมขนาดใหญ่ถูกเปรียบเทียบโดยไม่พึ่งพา integer-overflow saturation ดังนั้นค่า Range 30 หลักจึงถูกจัดการแบบไม่ขึ้นกับแพลตฟอร์ม ช่วงที่ตอบสนองได้และทับซ้อนกันจะถูกรวมก่อนที่จะสร้างเนื้อหาใด ๆ ส่วนช่วงที่แตกต่างกันอย่างแท้จริง (ไม่ทับซ้อน) จะถูกรักษาไว้เป็น multipart part แยกกัน
โหมดความล้มเหลวและแบบจำลองข้อยกเว้น
หัวข้อที่มีชื่อว่า “โหมดความล้มเหลวและแบบจำลองข้อยกเว้น”WebviewException เป็น marker interface ที่ขยายจาก Throwable ให้ catch มันเพื่อจัดการทั้งระบบย่อยอย่างเป็นเอกภาพ ข้อยกเว้นรูปธรรมทั้งสองอิมพลีเมนต์มัน
UnsupportedDocumentException(ขยายจากInvalidArgumentException) — ยกโดยLinearizedDocument::fromBytes()เมื่อไบต์ไม่ใช่เอกสาร linearized ที่ใช้งานได้ named constructor ได้แก่notLinearized()(ไม่มีพจนานุกรมพารามิเตอร์/Linearized),lengthMismatch($declaredLength, $actualLength)(/Lที่ประกาศไว้ไม่ตรงกับความยาวจริง ไม่ว่าจะถูกตัดทอน ถูกผนวกเกิน/Lผ่านการอัปเดตแบบ incremental หรือไม่เป็นไปตามข้อกำหนด) และmalformedFirstPageOffset($firstPageEndOffset, $length)(ออฟเซ็ต/Eไม่ใช่ออฟเซ็ตค่าบวกภายในไฟล์)RangeNotSatisfiableException(ขยายจากOutOfRangeException) — ข้อผิดพลาดของการ slice เชิงโปรแกรม ยกโดยByteRange::__construct()และLinearizedDocument::slice()/firstPageByteRange()เมื่อช่วงแบบ inclusive ตกอยู่นอกเอกสาร named constructor:outOfBounds($firstByte, $lastByte, $length)
ตัวตอบกลับ HTTP จะ ไม่ ยก RangeNotSatisfiableException สำหรับเฮดเดอร์ Range ของไคลเอนต์ ช่วง HTTP ที่ตอบสนองไม่ได้คือ การตอบกลับ 416 (RFC 9110 §15.3.7) ไม่ใช่ข้อยกเว้น ข้อยกเว้นนั้นถูกสงวนไว้สำหรับการ slice เชิงโปรแกรมโดยตรง ซึ่งคำขอที่อยู่นอกขอบเขตเป็นความผิดพลาดของผู้เรียกใช้ ByteRangeResponder::__construct() ยก InvalidArgumentException ธรรมดา (ไม่ใช่ WebviewException) เมื่อ contentType ที่กำหนดค่าไว้มีอักขระควบคุม
การเสริมความแข็งแกร่งต่อ denial-of-service
หัวข้อที่มีชื่อว่า “การเสริมความแข็งแกร่งต่อ denial-of-service”ตัวตอบกลับจำกัดจำนวนช่วงที่ถูกรวมและแตกต่างกันที่ยอมรับต่อคำขอ (ประเภท multipart range-amplification คือ Apache HTTPD CVE-2011-3192) เมื่อคำขอขอช่วงที่รวมกันแล้วมากกว่าเพดาน หรือขอจำนวนไบต์รวมมากกว่าการแทนเอกสารทั้งหมด Range จะถูกเพิกเฉยและคืนค่า 200 แบบเต็ม multipart boundary ถูกอนุมานแบบกำหนดได้แน่นอนและถูกอนุมานใหม่จนกว่าจะรับประกันได้ว่าจะไม่ปรากฏภายในเนื้อหา ซึ่งรักษาเอาต์พุตที่ทำซ้ำได้ในขณะที่ตัดความเป็นไปได้ของการชนกันของ boundary ออกไป
การเป็นไปตามมาตรฐาน
หัวข้อที่มีชื่อว่า “การเป็นไปตามมาตรฐาน”พฤติกรรมแบบ byte-range เป็นไปตาม RFC 9110 (HTTP Semantics) ได้แก่ §14 (คำขอช่วง), §13.1.5 (If-Range), §14.4 (Content-Range) และ §15.3.7 (416) การจัดวางเอกสาร linearized คือแบบจำลอง Fast Web View ของ ISO 32000-2 Annex F โมดูลนี้ไม่ยืนยันตัวระบุข้อกำหนดภายนอกเพิ่มเติมใดนอกเหนือจากพฤติกรรมที่การทดสอบของมันตรวจสอบยืนยันแล้ว
กรณีขอบและพฤติกรรมในโหมด FIPS
หัวข้อที่มีชื่อว่า “กรณีขอบและพฤติกรรมในโหมด FIPS”respondToBytes()ให้บริการช่วงเหนือไบต์ใด ๆ เมื่อไม่ต้องการความหมายเชิงหน้าแรก- ตัวตรวจสอบความถูกต้อง
If-Rangeแบบ HTTP-date จะถูกถือว่าไม่ตรงกัน →200แบบเต็ม (ไคลเอนต์เพียงดึงข้อมูลใหม่) ETagเป็นแฮช SHA-256 ที่ใช้เป็นตัวตรวจสอบความถูกต้องของแคชแบบ strong ล้วน ๆ โมดูลนี้ไม่ทำการลงลายเซ็นหรือการดำเนินการเข้ารหัสลับอื่นใด และไม่นิยามพฤติกรรมเฉพาะของ FIPS
ขอบเขตการเผยแพร่
หัวข้อที่มีชื่อว่า “ขอบเขตการเผยแพร่”หน้านี้บันทึกเฉพาะพฤติกรรมที่สังเกตได้จากภายนอกและพื้นผิว API สาธารณะที่รองรับเท่านั้น เส้นทาง namespace ภายใน คลาสตัวช่วย ตารางกลไก ชื่อไฟล์ runbook และคำนำหน้า ticket อยู่นอกขอบเขต