I'm implementing the range requests feature in ngx-extended-pdf-viewer to improve the loading performance of large PDF files.
Setup & expected behavior
I have added the following configuration in my Angular code:
<ngx-extended-pdf-viewer #pdfViewer
[src]="src"
[useBrowserLocale]="true">
pdfDefaultOptions.disableAutoFetch = true;
pdfDefaultOptions.disableStream = false;
pdfDefaultOptions.disableRange = false;
When using a static file path, such as:
this.src = '/assets/100MB-TESTFILE.pdf';
The 100 MB file starts rendering after loading just 10 MB, with the remaining data fetched progressively.
Issue
However, when I use an API-generated file URL, such as:
this.src = this.apiService.getDocumentFileURl();
getDocumentFileURl() {
return `${api_root}/document/${this.session.documentId}/version/${this.session.version}/view?language=${Helpers.getQueryParam('language', 'en')}&token=${this.session.token}`;
}
The PDF file is not displayed until 50 MB has been loaded, significantly increasing the loading time.
Back-end API implementation
The API responds to range requests using the following Java Jersey-based implementation:
@GET
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@Authorized
@Path("view")
public Response view(@QueryParam("language") String language, @Context ContainerRequestContext crc) throws Exception {
try {
String token = Token.getToken(crc);
UserDocument userDocument = (UserDocument) crc.getProperty(UserDocument.USER_DOCUMENT_KEY);
String filePath = userDocument.getVersion().getFileType() == FileType.VIDEO
? userDocument.getVersion().getFilePath()
: userDocument.getVersion().getPDFCopyPath();
if (!Files.exists(Paths.get(filePath))) {
return Response.status(Status.NOT_FOUND).build();
}
InputStream fileStream = Helpers.getFileInputStreamForRead(filePath);
long fileLength = fileStream.available();
String rangeHeader = crc.getHeaderString("Range");
if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
// Parse Range Header
String[] ranges = rangeHeader.substring("bytes=".length()).split("-");
long start = Long.parseLong(ranges[0]);
long end = ranges.length > 1 ? Long.parseLong(ranges[1]) : fileLength - 1;
// Validate range
if (start >= fileLength || end >= fileLength) {
return Response.status(Response.Status.REQUESTED_RANGE_NOT_SATISFIABLE)
.header("Content-Range", "bytes */" + fileLength)
.build();
}
long contentLength = end - start + 1;
fileStream.skip(start);
return Response.status(Response.Status.PARTIAL_CONTENT)
.entity(fileStream)
.header("Access-Control-Expose-Headers", "Accept-Ranges")
.header("Access-Control-Allow-Headers", "Accept-Ranges,range")
.header("Content-Range", "bytes " + start + "-" + end + "/" + fileLength)
.header("Accept-Ranges", "bytes")
.header("Content-Length", contentLength)
.header("Content-Type", "application/pdf; charset=UTF-8")
.build();
}
// If no Range header, return the entire file
return Response.ok()
.header("Access-Control-Expose-Headers", "Accept-Ranges")
.header("Access-Control-Allow-Headers", "Accept-Ranges,range")
.header("Accept-Ranges", "bytes")
.header("Content-Length", fileLength)
.header("Content-Type", "application/pdf; charset=UTF-8")
.entity(fileStream)
.build();
} catch (FileNotFoundException e) {
e.printStackTrace();
return Response.status(Response.Status.NOT_FOUND).build();
}
}
Question
How can I modify my implementation so that the dynamic API source behaves like the static source, allowing the PDF to load progressively after 10 MB, rather than requiring 50 MB before rendering begins?
Any insights into how ngx-extended-pdf-viewer handles range requests dynamically would be greatly appreciated.