diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a07fb0d62..e9e6dfe5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,31 +6,25 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - java: [jdk11, jdk15, graalvm] + java: [jdk11, jdk18, graalvm] fail-fast: false steps: - name: Check out the repository uses: actions/checkout@v2 - name: Test in Linux JDK 11 if: matrix.os == 'ubuntu-latest' && matrix.java == 'jdk11' - run: docker-compose -f docker/Linux-JDK11/docker-compose.yml up --exit-code-from cantaloupe - - name: Test in Linux JDK 15 - if: matrix.os == 'ubuntu-latest' && matrix.java == 'jdk15' - run: docker-compose -f docker/Linux-JDK15/docker-compose.yml up --exit-code-from cantaloupe - - name: Test in Linux JDK 16 - if: matrix.os == 'ubuntu-latest' && matrix.java == 'jdk16' - run: docker-compose -f docker/Linux-JDK16/docker-compose.yml up --exit-code-from cantaloupe + run: docker-compose -f docker/Linux-JDK11/docker-compose.yml up --build --exit-code-from cantaloupe + - name: Test in Linux JDK 18 + if: matrix.os == 'ubuntu-latest' && matrix.java == 'jdk18' + run: docker-compose -f docker/Linux-JDK18/docker-compose.yml up --build --exit-code-from cantaloupe - name: Test in Linux GraalVM if: matrix.os == 'ubuntu-latest' && matrix.java == 'graalvm' - run: docker-compose -f docker/Linux-GraalVM20/docker-compose.yml up --exit-code-from cantaloupe + run: docker-compose -f docker/Linux-GraalVM20/docker-compose.yml up --build --exit-code-from cantaloupe - name: Test in Windows JDK 11 if: matrix.os == 'windows-latest' && matrix.java == 'jdk11' - run: docker-compose -f docker/Windows-JDK11/docker-compose.yml up --exit-code-from cantaloupe - - name: Test in Windows JDK 15 - if: matrix.os == 'windows-latest' && matrix.java == 'jdk15' - run: docker-compose -f docker/Windows-JDK15/docker-compose.yml up --exit-code-from cantaloupe - - name: Test in Windows JDK 16 - if: matrix.os == 'windows-latest' && matrix.java == 'jdk16' - run: docker-compose -f docker/Windows-JDK16/docker-compose.yml up --exit-code-from cantaloupe + run: docker-compose -f docker/Windows-JDK11/docker-compose.yml up --build --exit-code-from cantaloupe + - name: Test in Windows JDK 18 + if: matrix.os == 'windows-latest' && matrix.java == 'jdk18' + run: docker-compose -f docker/Windows-JDK18/docker-compose.yml up --build --exit-code-from cantaloupe # TODO: Windows+GraalVM diff --git a/CHANGES.md b/CHANGES.md index 6146b708b..e3ac2baaa 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -37,10 +37,14 @@ ## 5.0.6 * IIIF information endpoints always return JSON in HTTP 4xx responses. +* Fixed a bug whereby the values of the `operations` and `page_count` keys + in the delegate context were not set. * TurboJpegProcessor is able to generate non-JPEG derivative images, which fixes an HTTP 415 error that would occur when trying to do that. * Fixed a crop-offset bug that could occur when using PdfBoxProcessor to generate JPEGs with libjpeg-turbo active. +* Updating libraries to fix security issues. Full details in [#634](https://github.com/cantaloupe-project/cantaloupe/issues/634) +* Update of Jena to 4.8 requires RDF to have a populated rdf:about field. May impact some XMP header processing. ## 5.0.5 diff --git a/CREDITS.md b/CREDITS.md new file mode 100644 index 000000000..e0849d234 --- /dev/null +++ b/CREDITS.md @@ -0,0 +1,9 @@ +# Credits + +The success of this project is down to the great work done by the developers at the University of Illinois and particularly Alex Dolski who has been the main developer on the project. In 2023 the IIIF consortium offered to help release a security patch as so many IIIF community members are using this great software. + +- Cantaloupe 5.0.6 + * [Glen Robson](https://github.com/glenrobson/) with support from the [IIIF Consortium](https://iiif.io/community/consortium/) + +- Cantaloupe v1 - v6 + * [Alex Dolski](https://github.com/adolski), University of Illinois \ No newline at end of file diff --git a/docker/Linux-GraalVM20/Dockerfile b/docker/Linux-GraalVM20/Dockerfile index 847a3795f..55b7c044c 100644 --- a/docker/Linux-GraalVM20/Dockerfile +++ b/docker/Linux-GraalVM20/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:latest +FROM ubuntu:lunar ENV JAVA_HOME=/opt/graalvm-ce-java11-20.3.0 ENV GRAALVM_HOME=/opt/graalvm-ce-java11-20.3.0 @@ -20,6 +20,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ zlib1g-dev \ libwebp-dev \ libimage-exiftool-perl \ + libgrokj2k1 \ + grokj2k-tools \ + adduser \ && rm -rf /var/lib/apt/lists/* # Install TurboJpegProcessor dependencies @@ -30,10 +33,10 @@ COPY docker/Linux-JDK11/image_files/libjpeg-turbo/lib64 /opt/libjpeg-turbo/lib COPY dist/deps/Linux-x86-64/lib/* /usr/lib/ # Install GrokProcessor dependencies -RUN wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/libgrokj2k1_7.6.5-1_amd64.deb \ - && wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/grokj2k-tools_7.6.5-1_amd64.deb \ - && dpkg -i ./libgrokj2k1_7.6.5-1_amd64.deb \ - && dpkg -i --ignore-depends=libjpeg62-turbo ./grokj2k-tools_7.6.5-1_amd64.deb +#RUN wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/libgrokj2k1_7.6.5-1_amd64.deb \ +# && wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/grokj2k-tools_7.6.5-1_amd64.deb \ +# && dpkg -i --ignore-depends=libjpeg62-turbo ./grokj2k-tools_7.6.5-1_amd64.deb +# && dpkg -i ./libgrokj2k1_7.6.5-1_amd64.deb \ # Install GraalVM RUN wget -q https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-20.3.0/graalvm-ce-java11-linux-amd64-20.3.0.tar.gz \ diff --git a/docker/Linux-JDK11/Dockerfile b/docker/Linux-JDK11/Dockerfile index fb3eab9d5..3129f9a73 100644 --- a/docker/Linux-JDK11/Dockerfile +++ b/docker/Linux-JDK11/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:latest +FROM ubuntu:lunar ARG DEBIAN_FRONTEND=noninteractive @@ -18,6 +18,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ zlib1g-dev \ libwebp-dev \ libimage-exiftool-perl \ + libgrokj2k1 \ + grokj2k-tools \ + adduser \ && rm -rf /var/lib/apt/lists/* # Install TurboJpegProcessor dependencies @@ -28,16 +31,16 @@ COPY docker/Linux-JDK11/image_files/libjpeg-turbo/lib64 /opt/libjpeg-turbo/lib COPY dist/deps/Linux-x86-64/lib/* /usr/lib/ # Install GrokProcessor dependencies -RUN wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/libgrokj2k1_7.6.5-1_amd64.deb \ - && wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/grokj2k-tools_7.6.5-1_amd64.deb \ - && dpkg -i ./libgrokj2k1_7.6.5-1_amd64.deb \ - && dpkg -i --ignore-depends=libjpeg62-turbo ./grokj2k-tools_7.6.5-1_amd64.deb +#RUN wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/libgrokj2k1_7.6.5-1_amd64.deb \ +# && wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/grokj2k-tools_7.6.5-1_amd64.deb \ +# && dpkg -i ./libgrokj2k1_7.6.5-1_amd64.deb \ +# && dpkg -i --ignore-depends=libjpeg62-turbo ./grokj2k-tools_7.6.5-1_amd64.deb # A non-root user is needed for some FilesystemSourceTest tests to work. ARG user=cantaloupe ARG home=/home/$user RUN adduser --home $home $user -RUN chown -R $user $home +RUN chown -R $user $home USER $user WORKDIR $home diff --git a/docker/Linux-JDK15/Dockerfile b/docker/Linux-JDK15/Dockerfile deleted file mode 100644 index d8ffc2296..000000000 --- a/docker/Linux-JDK15/Dockerfile +++ /dev/null @@ -1,57 +0,0 @@ -FROM ubuntu:latest - -ENV JAVA_HOME=/opt/jdk -ENV PATH=$PATH:/opt/jdk/bin -ARG DEBIAN_FRONTEND=noninteractive - -# Install various dependencies -RUN apt-get update && apt-get install -y --no-install-recommends \ - ffmpeg \ - maven \ - wget \ - libopenjp2-tools \ - liblcms2-dev \ - libpng-dev \ - libzstd-dev \ - libtiff-dev \ - libjpeg-dev \ - zlib1g-dev \ - libwebp-dev \ - libimage-exiftool-perl \ - && rm -rf /var/lib/apt/lists/* - -# Install TurboJpegProcessor dependencies -RUN mkdir -p /opt/libjpeg-turbo/lib -COPY docker/Linux-JDK11/image_files/libjpeg-turbo/lib64 /opt/libjpeg-turbo/lib - -# Install KakaduNativeProcessor dependencies -COPY dist/deps/Linux-x86-64/lib/* /usr/lib/ - -# Install GrokProcessor dependencies -RUN wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/libgrokj2k1_7.6.5-1_amd64.deb \ - && wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/grokj2k-tools_7.6.5-1_amd64.deb \ - && dpkg -i ./libgrokj2k1_7.6.5-1_amd64.deb \ - && dpkg -i --ignore-depends=libjpeg62-turbo ./grokj2k-tools_7.6.5-1_amd64.deb - -# Install OpenJDK -RUN wget -q https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9/OpenJDK15U-jdk_x64_linux_hotspot_15.0.1_9.tar.gz \ - && tar xfz OpenJDK15U-jdk_x64_linux_hotspot_15.0.1_9.tar.gz \ - && mv jdk-15.0.1+9 /opt/jdk - -# A non-root user is needed for some FilesystemSourceTest tests to work. -ARG user=cantaloupe -ARG home=/home/$user -RUN adduser --home $home $user -RUN chown -R $user $home -USER $user -WORKDIR $home - -# Install application dependencies -COPY ./pom.xml pom.xml -RUN mvn --quiet dependency:resolve - -# Copy the code -COPY --chown=cantaloupe docker/Linux-JDK11/image_files/test.properties test.properties -COPY --chown=cantaloupe ./src src - -ENTRYPOINT mvn --batch-mode test -Pfreedeps \ No newline at end of file diff --git a/docker/Linux-JDK15/docker-compose.yml b/docker/Linux-JDK15/docker-compose.yml deleted file mode 100644 index 4b4136275..000000000 --- a/docker/Linux-JDK15/docker-compose.yml +++ /dev/null @@ -1,21 +0,0 @@ -# -# N.B.: docker-compose must be invoked from the project root directory: -# -# docker-compose -f path/to/docker-compose.yml up --exit-code-from cantaloupe -# -version: '3' -services: - cantaloupe: - build: - context: ../../ - dockerfile: $PWD/docker/Linux-JDK15/Dockerfile - minio: - image: minio/minio - environment: - MINIO_ACCESS_KEY: MinioUser - MINIO_SECRET_KEY: OpenSesame - hostname: minio - command: server /data - redis: - image: redis:alpine - hostname: redis \ No newline at end of file diff --git a/docker/Linux-JDK16/Dockerfile b/docker/Linux-JDK18/Dockerfile similarity index 61% rename from docker/Linux-JDK16/Dockerfile rename to docker/Linux-JDK18/Dockerfile index 34e828755..ac131292b 100644 --- a/docker/Linux-JDK16/Dockerfile +++ b/docker/Linux-JDK18/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:latest +FROM ubuntu:lunar ENV JAVA_HOME=/opt/jdk ENV PATH=$PATH:/opt/jdk/bin:/opt/maven/bin @@ -23,6 +23,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ zlib1g-dev \ libwebp-dev \ libimage-exiftool-perl \ + libgrokj2k1 \ + grokj2k-tools \ + adduser \ && rm -rf /var/lib/apt/lists/* # Install TurboJpegProcessor dependencies @@ -34,19 +37,19 @@ COPY dist/deps/Linux-x86-64/lib/* /usr/lib/ # Install various other dependencies that aren't in apt # Install GrokProcessor dependencies -RUN wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/libgrokj2k1_7.6.5-1_amd64.deb \ - && wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/grokj2k-tools_7.6.5-1_amd64.deb \ - && dpkg -i ./libgrokj2k1_7.6.5-1_amd64.deb \ - && dpkg -i --ignore-depends=libjpeg62-turbo ./grokj2k-tools_7.6.5-1_amd64.deb \ +#RUN wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/libgrokj2k1_7.6.5-1_amd64.deb \ +# && wget -q https://github.com/GrokImageCompression/grok/releases/download/v7.6.5/grokj2k-tools_7.6.5-1_amd64.deb \ +# && dpkg -i ./libgrokj2k1_7.6.5-1_amd64.deb \ +# && dpkg -i --ignore-depends=libjpeg62-turbo ./grokj2k-tools_7.6.5-1_amd64.deb \ # Install OpenJDK - && wget -q https://github.com/AdoptOpenJDK/openjdk16-binaries/releases/download/jdk-16.0.1%2B9/OpenJDK16U-jdk_x64_linux_hotspot_16.0.1_9.tar.gz \ - && tar xfz OpenJDK16U-jdk_x64_linux_hotspot_16.0.1_9.tar.gz \ - && mv jdk-16.0.1+9 /opt/jdk \ - # Install Maven (the one in apt is too old for JDK16 as of 2020-05-14) - && wget -q https://mirrors.ocf.berkeley.edu/apache/maven/maven-3/3.8.1/binaries/apache-maven-3.8.1-bin.tar.gz \ - && tar xfz apache-maven-3.8.1-bin.tar.gz \ - && mv apache-maven-3.8.1 /opt/maven \ - && rm apache-maven-3.8.1-bin.tar.gz +RUN wget -q https://download.java.net/java/GA/jdk18/43f95e8614114aeaa8e8a5fcf20a682d/36/GPL/openjdk-18_linux-x64_bin.tar.gz \ + && tar xfz openjdk-18_linux-x64_bin.tar.gz \ + && mv jdk-18 /opt/jdk \ + # Install a newer Maven than the one in apt + && wget -q https://dlcdn.apache.org/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz \ + && tar xfz apache-maven-3.8.8-bin.tar.gz \ + && mv apache-maven-3.8.8 /opt/maven \ + && rm apache-maven-3.8.8-bin.tar.gz # A non-root user is needed for some FilesystemSourceTest tests to work. ARG user=cantaloupe diff --git a/docker/Linux-JDK16/docker-compose.yml b/docker/Linux-JDK18/docker-compose.yml similarity index 89% rename from docker/Linux-JDK16/docker-compose.yml rename to docker/Linux-JDK18/docker-compose.yml index b6518c805..7b2572bc0 100644 --- a/docker/Linux-JDK16/docker-compose.yml +++ b/docker/Linux-JDK18/docker-compose.yml @@ -8,7 +8,7 @@ services: cantaloupe: build: context: ../../ - dockerfile: $PWD/docker/Linux-JDK16/Dockerfile + dockerfile: $PWD/docker/Linux-JDK18/Dockerfile minio: image: minio/minio environment: diff --git a/docker/Windows-JDK11/Dockerfile b/docker/Windows-JDK11/Dockerfile index 8d81bd6d1..ba1008de8 100644 --- a/docker/Windows-JDK11/Dockerfile +++ b/docker/Windows-JDK11/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/windows/servercore:ltsc2019 +FROM mcr.microsoft.com/windows/servercore:ltsc2022 ENV chocolateyUseWindowsCompression false diff --git a/docker/Windows-JDK11/Dockerfile-minio b/docker/Windows-JDK11/Dockerfile-minio index b213b8746..115389668 100644 --- a/docker/Windows-JDK11/Dockerfile-minio +++ b/docker/Windows-JDK11/Dockerfile-minio @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/windows/servercore:ltsc2019 +FROM mcr.microsoft.com/windows/servercore:ltsc2022 ENV MINIO_ACCESS_KEY=MinioUser ENV MINIO_SECRET_KEY=OpenSesame diff --git a/docker/Windows-JDK15/Dockerfile b/docker/Windows-JDK15/Dockerfile deleted file mode 100644 index 79307a09a..000000000 --- a/docker/Windows-JDK15/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM mcr.microsoft.com/windows/servercore:ltsc2019 - -ENV chocolateyUseWindowsCompression false - -# Install the Chocolatey package manager, which makes it easier to install -# dependencies. -RUN powershell -Command \ - iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')); \ - choco feature disable --name showDownloadProgress - -# Install various dependencies -# TODO: openjpeg -RUN choco install -y adoptopenjdk15 maven ffmpeg - -# Install TurboJpegProcessor dependencies TODO: libjpeg-turbo -#RUN mkdir -p /opt/libjpeg-turbo/lib -#COPY docker/Windows10-JDK11/image_files/libjpeg-turbo/lib64 c:\windows\system32 - -# Install KakaduNativeProcessor dependencies -COPY dist/deps/Windows-x86-64/lib/* c:/Windows/System32/ - -# Install application dependencies -COPY pom.xml pom.xml -RUN mvn dependency:resolve - -# Copy the code -COPY docker/Windows-JDK11/image_files/test.properties test.properties -COPY src src \ No newline at end of file diff --git a/docker/Windows-JDK15/Dockerfile-minio b/docker/Windows-JDK15/Dockerfile-minio deleted file mode 100644 index babcdadfd..000000000 --- a/docker/Windows-JDK15/Dockerfile-minio +++ /dev/null @@ -1,10 +0,0 @@ -FROM mcr.microsoft.com/windows/servercore:ltsc2019 - -ENV MINIO_ACCESS_KEY=MinioUser -ENV MINIO_SECRET_KEY=OpenSesame - -RUN curl.exe --output minio.exe --url https://dl.min.io/server/minio/release/windows-amd64/minio.exe - -RUN mkdir c:\data - -CMD minio.exe server --address=:9000 c:\data \ No newline at end of file diff --git a/docker/Windows-JDK15/docker-compose.yml b/docker/Windows-JDK15/docker-compose.yml deleted file mode 100644 index e2c44b801..000000000 --- a/docker/Windows-JDK15/docker-compose.yml +++ /dev/null @@ -1,19 +0,0 @@ -# -# N.B.: docker-compose must be invoked from the project root directory: -# -# docker-compose -f path/to/docker-compose.yml up --exit-code-from cantaloupe -# -version: '3' -services: - cantaloupe: - build: - context: ../../ - dockerfile: docker/Windows-JDK15/Dockerfile - minio: - build: - context: ../../ - dockerfile: docker/Windows-JDK15/Dockerfile-minio - environment: - MINIO_ACCESS_KEY: MinioUser - MINIO_SECRET_KEY: OpenSesame - hostname: minio \ No newline at end of file diff --git a/docker/Windows-JDK16/Dockerfile b/docker/Windows-JDK18/Dockerfile similarity index 86% rename from docker/Windows-JDK16/Dockerfile rename to docker/Windows-JDK18/Dockerfile index dc0c9673a..e3f570efc 100644 --- a/docker/Windows-JDK16/Dockerfile +++ b/docker/Windows-JDK18/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/windows/servercore:ltsc2019 +FROM mcr.microsoft.com/windows/servercore:ltsc2022 ENV chocolateyUseWindowsCompression false @@ -10,8 +10,9 @@ RUN powershell -Command \ # Install various dependencies # TODO: openjpeg -RUN choco install -y adoptopenjdk16 maven ffmpeg - +RUN choco install -y maven ffmpeg +RUN choco install -y openjdk --version=18.0.2 + # Install TurboJpegProcessor dependencies TODO: libjpeg-turbo #RUN mkdir -p /opt/libjpeg-turbo/lib #COPY docker/Windows10-JDK11/image_files/libjpeg-turbo/lib64 c:\windows\system32 diff --git a/docker/Windows-JDK16/Dockerfile-minio b/docker/Windows-JDK18/Dockerfile-minio similarity index 81% rename from docker/Windows-JDK16/Dockerfile-minio rename to docker/Windows-JDK18/Dockerfile-minio index b213b8746..115389668 100644 --- a/docker/Windows-JDK16/Dockerfile-minio +++ b/docker/Windows-JDK18/Dockerfile-minio @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/windows/servercore:ltsc2019 +FROM mcr.microsoft.com/windows/servercore:ltsc2022 ENV MINIO_ACCESS_KEY=MinioUser ENV MINIO_SECRET_KEY=OpenSesame diff --git a/docker/Windows-JDK16/docker-compose.yml b/docker/Windows-JDK18/docker-compose.yml similarity index 77% rename from docker/Windows-JDK16/docker-compose.yml rename to docker/Windows-JDK18/docker-compose.yml index 1a505d28b..3c5812953 100644 --- a/docker/Windows-JDK16/docker-compose.yml +++ b/docker/Windows-JDK18/docker-compose.yml @@ -8,11 +8,11 @@ services: cantaloupe: build: context: ../../ - dockerfile: docker/Windows-JDK16/Dockerfile + dockerfile: docker/Windows-JDK18/Dockerfile minio: build: context: ../../ - dockerfile: docker/Windows-JDK16/Dockerfile-minio + dockerfile: docker/Windows-JDK18/Dockerfile-minio environment: MINIO_ACCESS_KEY: MinioUser MINIO_SECRET_KEY: OpenSesame diff --git a/pom.xml b/pom.xml index 6f0550f0c..fb8027428 100644 --- a/pom.xml +++ b/pom.xml @@ -15,12 +15,16 @@ 11 UTF-8 UTF-8 - 2.15.28 - 2.11.0 + 2.21.4 + 2.15.2 + + 11.0.5 - 9.2.17.0 - 1.2.8 - 3.0.0-M3 + 9.4.3.0 + 3.0.0-M5 + 2.53.1 + 1.2.13 + 1.7.36 @@ -70,25 +74,25 @@ net.logstash.logback logstash-logback-encoder - 6.1 + 7.4 com.github.ben-manes.caffeine caffeine - 2.5.6 + 3.1.6 com.google.protobuf protobuf-java - 3.5.1 + 4.0.0-rc-2 com.h2database h2 - 1.4.196 + 2.2.220 test @@ -101,19 +105,19 @@ com.microsoft.azure azure-storage - 5.2.0 + 8.6.6 com.squareup.okhttp3 okhttp - 3.13.1 + 5.0.0-alpha.12 com.zaxxer HikariCP - 2.7.2 + 4.0.3 @@ -126,7 +130,7 @@ commons-io commons-io - 2.4 + 2.13.0 edu.illinois.library @@ -137,63 +141,64 @@ io.lettuce lettuce-core - 6.0.1.RELEASE + 6.2.7.RELEASE javax.xml.bind jaxb-api - 2.3.0 + 2.4.0-b180830.0359 it.geosolutions.imageio-ext imageio-ext-tiff + 1.3.2 javax.servlet javax.servlet-api - 3.1.0 + 4.0.1 org.apache.commons commons-lang3 - 3.6 + 3.12.0 org.apache.pdfbox pdfbox - 2.0.23 + 2.0.29 org.apache.pdfbox jbig2-imageio - 3.0.3 + 3.0.4 org.junit.jupiter junit-jupiter-engine - 5.4.2 + 5.10.0-RC1 test org.openjdk.jmh jmh-core - 1.19 + 1.36 test org.openjdk.jmh jmh-generator-annprocess - 1.19 + 1.36 test org.apache.tika tika-core - 1.24.1 + 2.8.0 org.bouncycastle - bcprov-jdk15on - 1.64 + bcprov-jdk18on + 1.76 org.codehaus.janino janino - 2.7.8 + 3.1.10 @@ -330,45 +335,45 @@ org.apache.velocity velocity-engine-core - 2.0 + 2.3 org.seleniumhq.selenium htmlunit-driver - 2.21 + 2.21 test org.seleniumhq.selenium selenium-api - 2.53.0 + ${seleniumhq.version} test org.seleniumhq.selenium selenium-support - 2.53.0 + ${seleniumhq.version} test org.slf4j slf4j-api - 1.7.25 + ${slf4j.version} org.slf4j jcl-over-slf4j - 1.7.25 + ${slf4j.version} org.apache.maven.plugins maven-assembly-plugin - 3.1.1 + 3.6.0 maven-plugin @@ -420,8 +425,9 @@ random false - - --illegal-access=permit + + + --add-opens java.desktop/sun.awt.image=ALL-UNNAMED --illegal-access=permit @@ -429,13 +435,13 @@ com.github.spotbugs spotbugs-maven-plugin - 4.1.3 + 4.8.3.0 com.github.spotbugs spotbugs - 4.1.4 + 4.8.3 @@ -499,7 +505,7 @@ maven-assembly-plugin - 3.1.1 + 3.6.0 package @@ -530,7 +536,7 @@ org.owasp dependency-check-maven - 5.2.4 + 9.0.9 @@ -557,6 +563,8 @@ random false + + --add-opens java.desktop/sun.awt.image=ALL-UNNAMED AzureStorage*Test FfmpegProcessorTest @@ -586,6 +594,8 @@ random false + + --add-opens java.desktop/sun.awt.image=ALL-UNNAMED Azure*Test diff --git a/src/main/java/edu/illinois/library/cantaloupe/cache/JdbcCache.java b/src/main/java/edu/illinois/library/cantaloupe/cache/JdbcCache.java index f147f0700..58ce6caca 100644 --- a/src/main/java/edu/illinois/library/cantaloupe/cache/JdbcCache.java +++ b/src/main/java/edu/illinois/library/cantaloupe/cache/JdbcCache.java @@ -102,7 +102,9 @@ public void close() throws IOException { throw new IOException(e.getMessage(), e); } finally { try { - statement.close(); + if (statement != null) { + statement.close(); + } } catch (SQLException e) { LOGGER.error(e.getMessage(), e); } @@ -361,7 +363,7 @@ public InputStream newDerivativeImageInputStream(OperationList opList) DERIVATIVE_IMAGE_TABLE_LAST_ACCESSED_COLUMN); try (Connection conn = getConnection(); - PreparedStatement statement = conn.prepareStatement(sql)) { + PreparedStatement statement = conn.prepareStatement(sql)) { statement.setString(1, opList.toString()); statement.setTimestamp(2, earliestValidDate()); @@ -390,6 +392,7 @@ public InputStream newDerivativeImageInputStream(OperationList opList) try { return new ImageBlobOutputStream(getConnection(), ops); } catch (SQLException e) { + LOGGER.error("Throwing Except: {}", e); throw new IOException(e.getMessage(), e); } } diff --git a/src/main/java/edu/illinois/library/cantaloupe/image/MediaType.java b/src/main/java/edu/illinois/library/cantaloupe/image/MediaType.java index 1c4b0b367..d5370f3c0 100644 --- a/src/main/java/edu/illinois/library/cantaloupe/image/MediaType.java +++ b/src/main/java/edu/illinois/library/cantaloupe/image/MediaType.java @@ -12,6 +12,7 @@ import org.apache.tika.detect.Detector; import org.apache.tika.io.TikaInputStream; import org.apache.tika.metadata.Metadata; +import org.apache.tika.metadata.TikaCoreProperties; import org.apache.tika.parser.AutoDetectParser; import java.io.IOException; @@ -99,7 +100,7 @@ public static List detectMediaTypes(Path path) AutoDetectParser parser = new AutoDetectParser(); Detector detector = parser.getDetector(); Metadata md = new Metadata(); - md.add(Metadata.RESOURCE_NAME_KEY, path.toString()); + md.add(TikaCoreProperties.RESOURCE_NAME_KEY, path.toString()); org.apache.tika.mime.MediaType mediaType = detector.detect(is, md); types.add(new MediaType(mediaType.toString())); } diff --git a/src/main/java/edu/illinois/library/cantaloupe/image/Metadata.java b/src/main/java/edu/illinois/library/cantaloupe/image/Metadata.java index 1baa942c2..8a2d26819 100644 --- a/src/main/java/edu/illinois/library/cantaloupe/image/Metadata.java +++ b/src/main/java/edu/illinois/library/cantaloupe/image/Metadata.java @@ -123,6 +123,9 @@ public Orientation getOrientation() { } catch (IllegalArgumentException e) { LOGGER.info("readOrientation(): {}", e.getMessage()); orientation = Orientation.ROTATE_0; + } catch (RiotException e) { + LOGGER.info("readOrientation(): {}", e.getMessage()); + orientation = Orientation.ROTATE_0; } } return orientation; @@ -209,10 +212,27 @@ private void loadXMP() { RIOT.init(); xmpModel = ModelFactory.createDefaultModel(); + String base = null; + if (xmp.get().indexOf("rdf:about=''") != -1 || xmp.get().indexOf("rdf:about=\"\"") != -1) { + // Version 4.8+ of jena requires a rdf:about link to not be empty + base = "http://example.com"; + } try (StringReader reader = new StringReader(xmp.get())) { - xmpModel.read(reader, null, "RDF/XML"); - } catch (RiotException | NullPointerException e) { + xmpModel.read(reader, base, "RDF/XML"); + } catch (RiotException e) { + if (e.getMessage().indexOf("Base URI is null, but there are relative URIs to resolve") != -1) { + // Version 4.8+ of jena requires a rdf:about link to not be empty + try (StringReader reader = new StringReader(xmp.get())) { + xmpModel.read(reader, "http://example.com", "RDF/XML"); + } catch (RiotException exception) { + LOGGER.info("loadXMP(): {}", exception.getMessage()); + } + } else { + LOGGER.info("loadXMP(): {}", e.getMessage()); + throw e; + } + } catch (NullPointerException e) { // The XMP string may be invalid RDF/XML, or there may be a bug // in Jena (that would be the NPE). Not much we can do. LOGGER.info("loadXMP(): {}", e.getMessage()); diff --git a/src/main/java/edu/illinois/library/cantaloupe/processor/PdfBoxProcessor.java b/src/main/java/edu/illinois/library/cantaloupe/processor/PdfBoxProcessor.java index 0197feab7..6de50010c 100644 --- a/src/main/java/edu/illinois/library/cantaloupe/processor/PdfBoxProcessor.java +++ b/src/main/java/edu/illinois/library/cantaloupe/processor/PdfBoxProcessor.java @@ -142,7 +142,8 @@ public boolean isSeeking() { private void readDocument() throws IOException { if (doc == null) { final Stopwatch watch = new Stopwatch(); - + // For PDF Box v3 this would need to change to a loader: + // https://pdfbox.apache.org/3.0/migration.html#use-loader-to-get-a-pdf-document if (sourceFile != null) { doc = PDDocument.load(sourceFile.toFile(), getMemoryUsageSetting()); diff --git a/src/main/java/edu/illinois/library/cantaloupe/processor/codec/jpeg/Util.java b/src/main/java/edu/illinois/library/cantaloupe/processor/codec/jpeg/Util.java index b1fce36b0..c73507dd4 100644 --- a/src/main/java/edu/illinois/library/cantaloupe/processor/codec/jpeg/Util.java +++ b/src/main/java/edu/illinois/library/cantaloupe/processor/codec/jpeg/Util.java @@ -6,6 +6,7 @@ import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.rdf.model.StmtIterator; +import org.apache.jena.riot.RiotException; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -119,8 +120,18 @@ private static String mergeXMPModels(String standardXMP, private static Model readModel(String rdfXML) { Model model = ModelFactory.createDefaultModel(); + String base = null; try (StringReader reader = new StringReader(rdfXML)) { - model.read(reader, null, "RDF/XML"); + model.read(reader, base, "RDF/XML"); + } catch (RiotException exception) { + if (exception.getMessage().indexOf("Base URI is null, but there are relative URIs to resolve") != -1) { + // Version 4.8+ of jena requires a rdf:about link to not be empty + try (StringReader reader = new StringReader(rdfXML)) { + model.read(reader, "http://example.com", "RDF/XML"); + } + } else { + throw exception; + } } return model; } diff --git a/src/main/java/edu/illinois/library/cantaloupe/resource/ImageRequestHandler.java b/src/main/java/edu/illinois/library/cantaloupe/resource/ImageRequestHandler.java index 57a7b2cf1..31f1cfb6f 100644 --- a/src/main/java/edu/illinois/library/cantaloupe/resource/ImageRequestHandler.java +++ b/src/main/java/edu/illinois/library/cantaloupe/resource/ImageRequestHandler.java @@ -398,10 +398,12 @@ public void handle(OutputStream outputStream) throws Exception { try { fullSize = info.getSize(operationList.getPageIndex()); requestContext.setMetadata(info.getMetadata()); - operationList.applyNonEndpointMutations(info, delegateProxy); - operationList.freeze(); requestContext.setOperationList(operationList, fullSize); requestContext.setPageCount(info.getNumPages()); + // This must be done *after* the request context is fully + // populated, as some of the mutations may depend on it. + operationList.applyNonEndpointMutations(info, delegateProxy); + operationList.freeze(); } catch (IllegalArgumentException | IndexOutOfBoundsException e) { throw new IllegalClientArgumentException(e); } diff --git a/src/test/java/edu/illinois/library/cantaloupe/cache/AbstractCacheTest.java b/src/test/java/edu/illinois/library/cantaloupe/cache/AbstractCacheTest.java index f2260977b..8b04f03d6 100644 --- a/src/test/java/edu/illinois/library/cantaloupe/cache/AbstractCacheTest.java +++ b/src/test/java/edu/illinois/library/cantaloupe/cache/AbstractCacheTest.java @@ -325,6 +325,9 @@ void testPurge() throws Exception { // purge everything instance.purge(); + // Allow time for purge but not as long as upload + Thread.sleep(ASYNC_WAIT / 2); + // assert that the info has been purged assertFalse(instance.getInfo(identifier).isPresent()); diff --git a/src/test/java/edu/illinois/library/cantaloupe/cache/S3CacheTest.java b/src/test/java/edu/illinois/library/cantaloupe/cache/S3CacheTest.java index 1d534c6c2..6f00ec903 100644 --- a/src/test/java/edu/illinois/library/cantaloupe/cache/S3CacheTest.java +++ b/src/test/java/edu/illinois/library/cantaloupe/cache/S3CacheTest.java @@ -317,6 +317,9 @@ void testPurgeWithKeyPrefix() throws Exception { // purge everything instance.purge(); + // Allow some time for the purge to succeed + Thread.sleep(ASYNC_WAIT / 2); + // assert that the info has been purged assertFalse(instance.getInfo(identifier).isPresent()); diff --git a/src/test/java/edu/illinois/library/cantaloupe/image/MetadataTest.java b/src/test/java/edu/illinois/library/cantaloupe/image/MetadataTest.java index 366c9cb77..de3d914f6 100644 --- a/src/test/java/edu/illinois/library/cantaloupe/image/MetadataTest.java +++ b/src/test/java/edu/illinois/library/cantaloupe/image/MetadataTest.java @@ -12,6 +12,8 @@ import edu.illinois.library.cantaloupe.test.BaseTest; import edu.illinois.library.cantaloupe.test.TestUtil; import org.apache.jena.rdf.model.Model; +import org.apache.jena.riot.RDFDataMgr; +import org.apache.jena.riot.RDFFormat; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -444,7 +446,7 @@ void testToMap() { expectedMap.put("iptc", List.of(new DataSet( edu.illinois.library.cantaloupe.image.iptc.Tag.CITY, "Urbana".getBytes()).toMap())); - expectedMap.put("xmp_string", ""); + expectedMap.put("xmp_string", ""); expectedMap.put("xmp_elements", Collections.emptyMap()); expectedMap.put("native", Map.of("key1", "value1", "key2", "value2")); @@ -464,7 +466,7 @@ void testToMap() { "Urbana".getBytes())); instance.setIPTC(iptc); // XMP - instance.setXMP(""); + instance.setXMP(""); // native instance.setNativeMetadata(Map.of("key1", "value1", "key2", "value2")); diff --git a/src/test/java/edu/illinois/library/cantaloupe/operation/EncodeTest.java b/src/test/java/edu/illinois/library/cantaloupe/operation/EncodeTest.java index ee8f5b614..0fc0b9aac 100644 --- a/src/test/java/edu/illinois/library/cantaloupe/operation/EncodeTest.java +++ b/src/test/java/edu/illinois/library/cantaloupe/operation/EncodeTest.java @@ -137,7 +137,7 @@ void testToMap() { instance.setBackgroundColor(Color.BLUE); instance.setMaxComponentSize(10); Metadata metadata = new Metadata(); - metadata.setXMP(""); + metadata.setXMP(""); instance.setMetadata(metadata); Dimension size = new Dimension(500, 500); @@ -150,7 +150,7 @@ void testToMap() { assertTrue((boolean) map.get("interlace")); assertEquals(50, map.get("quality")); assertEquals(10, map.get("max_sample_size")); - assertEquals("", + assertEquals("", ((Map) map.get("metadata")).get("xmp_string")); } diff --git a/src/test/java/edu/illinois/library/cantaloupe/processor/codec/png/PNGMetadataTest.java b/src/test/java/edu/illinois/library/cantaloupe/processor/codec/png/PNGMetadataTest.java index cf709ab1a..31ddace80 100644 --- a/src/test/java/edu/illinois/library/cantaloupe/processor/codec/png/PNGMetadataTest.java +++ b/src/test/java/edu/illinois/library/cantaloupe/processor/codec/png/PNGMetadataTest.java @@ -45,9 +45,10 @@ void testGetNativeMetadata() throws IOException { @Test void testGetXMP() throws IOException { - final String rdf = getInstance("png-xmp.png").getXMP().orElseThrow(); + final String fixtureName = "png-xmp.png"; + final String rdf = getInstance(fixtureName).getXMP().orElseThrow(); final Model model = ModelFactory.createDefaultModel(); - model.read(new StringReader(rdf), null, "RDF/XML"); + model.read(new StringReader(rdf), "file://" + TestUtil.getImage(fixtureName).getParent().toAbsolutePath(), "RDF/XML"); } } diff --git a/src/test/java/edu/illinois/library/cantaloupe/processor/codec/tiff/TIFFMetadataTest.java b/src/test/java/edu/illinois/library/cantaloupe/processor/codec/tiff/TIFFMetadataTest.java index 7104e06be..132cf7bc9 100644 --- a/src/test/java/edu/illinois/library/cantaloupe/processor/codec/tiff/TIFFMetadataTest.java +++ b/src/test/java/edu/illinois/library/cantaloupe/processor/codec/tiff/TIFFMetadataTest.java @@ -4,6 +4,8 @@ import edu.illinois.library.cantaloupe.test.TestUtil; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.riot.RDFDataMgr; +import org.apache.jena.riot.RDFFormat; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -80,7 +82,7 @@ void testGetXMP() throws IOException { try (ImageInputStream is = ImageIO.createImageInputStream(srcFile.toFile())) { final String rdf = newInstance(is).getXMP().orElseThrow(); final Model model = ModelFactory.createDefaultModel(); - model.read(new StringReader(rdf), null, "RDF/XML"); + model.read(new StringReader(rdf), "file://" + srcFile.getParent().toAbsolutePath(), "RDF/XML"); } } diff --git a/src/test/resources/delegates.rb b/src/test/resources/delegates.rb index 3ad145081..509ee0dda 100644 --- a/src/test/resources/delegates.rb +++ b/src/test/resources/delegates.rb @@ -2,6 +2,7 @@ require 'java' require 'uri' +require 'cgi' class CustomDelegate @@ -166,11 +167,11 @@ def httpsource_resource_info(options = {}) elsif context['client_ip'] == '1.2.3.4' if context['request_headers']['X-Forwarded-Proto'] == 'https' return { - 'uri' => 'https://other-example.org/bleh/' + URI.escape(identifier) + 'uri' => 'https://other-example.org/bleh/' + CGI.escape(identifier) } else return { - 'uri' => 'http://other-example.org/bleh/' + URI.escape(identifier) + 'uri' => 'http://other-example.org/bleh/' + CGI.escape(identifier) } end end @@ -178,7 +179,7 @@ def httpsource_resource_info(options = {}) case identifier when 'http-jpg-rgb-64x56x8-baseline.jpg' return { - 'uri' => 'http://example.org/bla/' + URI.escape(identifier), + 'uri' => 'http://example.org/bla/' + CGI.escape(identifier), 'headers' => { 'X-Custom' => 'yes' }, @@ -186,7 +187,7 @@ def httpsource_resource_info(options = {}) } when 'https-jpg-rgb-64x56x8-baseline.jpg' return { - 'uri' => 'https://example.org/bla/' + URI.escape(identifier), + 'uri' => 'https://example.org/bla/' + CGI.escape(identifier), 'headers' => { 'X-Custom' => 'yes' }, @@ -194,7 +195,7 @@ def httpsource_resource_info(options = {}) } when 'http-jpg-rgb-64x56x8-plane.jpg' return { - 'uri' => 'http://example.org/bla/' + URI.escape(identifier), + 'uri' => 'http://example.org/bla/' + CGI.escape(identifier), 'username' => 'username', 'secret' => 'secret', 'headers' => { @@ -204,7 +205,7 @@ def httpsource_resource_info(options = {}) } when 'https-jpg-rgb-64x56x8-plane.jpg' return { - 'uri' => 'https://example.org/bla/' + URI.escape(identifier), + 'uri' => 'https://example.org/bla/' + CGI.escape(identifier), 'username' => 'username', 'secret' => 'secret', 'headers' => {