Skip to content

Commit

Permalink
feat: Support IIIF Image's API HEAD requests (DEV-4072)
Browse files Browse the repository at this point in the history
  • Loading branch information
siers committed Sep 24, 2024
1 parent d5eaab3 commit 6389403
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 22 deletions.
14 changes: 8 additions & 6 deletions src/SipiHttpServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,7 @@ static void serve_iiif(Connection &conn_obj,
const std::string &uri,
std::vector<std::string> params)
{
auto headRequest = conn_obj.method() != Connection::HEAD;
//
// getting the identifier (which in case of a PDF or multipage TIFF my contain a page id (identifier@pagenum)
//
Expand Down Expand Up @@ -1387,7 +1388,7 @@ static void serve_iiif(Connection &conn_obj,
}
}
try {
conn_obj.sendFile(infile);
if (headRequest) conn_obj.sendFile(infile);
} catch (shttps::InputFailure iofail) {
syslog(LOG_WARNING, "Browser unexpectedly closed connection");
} catch (Sipi::SipiError &err) {
Expand Down Expand Up @@ -1430,7 +1431,7 @@ static void serve_iiif(Connection &conn_obj,

try {
//!> send the file from cache
conn_obj.sendFile(cachefile);
if (headRequest) conn_obj.sendFile(cachefile);
//!> from now on the cache file can be deleted again
} catch (shttps::InputFailure err) {
// -1 was thrown
Expand Down Expand Up @@ -1530,15 +1531,15 @@ static void serve_iiif(Connection &conn_obj,
conn_obj.header("Content-Type", "image/jpeg");// set the header (mimetype)
conn_obj.setChunkedTransfer();
Sipi::SipiCompressionParams qp = { { JPEG_QUALITY, std::to_string(server->jpeg_quality()) } };
img.write("jpg", "HTTP", &qp);
if (headRequest) img.write("jpg", "HTTP", &qp);
break;
}
case SipiQualityFormat::JP2: {
conn_obj.status(Connection::OK);
conn_obj.header("Link", canonical_header);
conn_obj.header("Content-Type", "image/jp2");// set the header (mimetype)
conn_obj.setChunkedTransfer();
img.write("jpx", "HTTP");
if (headRequest) img.write("jpx", "HTTP");
break;
}
case SipiQualityFormat::TIF: {
Expand All @@ -1547,7 +1548,7 @@ static void serve_iiif(Connection &conn_obj,
conn_obj.header("Content-Type", "image/tiff");// set the header (mimetype)
// no chunked transfer needed...

img.write("tif", "HTTP");
if (headRequest) img.write("tif", "HTTP");
break;
}
case SipiQualityFormat::PNG: {
Expand All @@ -1556,7 +1557,7 @@ static void serve_iiif(Connection &conn_obj,
conn_obj.header("Content-Type", "image/png");// set the header (mimetype)
conn_obj.setChunkedTransfer();

img.write("png", "HTTP");
if (headRequest) img.write("png", "HTTP");
break;
}
default: {
Expand Down Expand Up @@ -1701,6 +1702,7 @@ void SipiHttpServer::run()

add_route(Connection::GET, "/favicon.ico", favicon_handler);
add_route(Connection::GET, "/", iiif_handler);
add_route(Connection::HEAD, "/", iiif_handler);

user_data(this);

Expand Down
14 changes: 6 additions & 8 deletions test/e2e/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ def compare_server_images(self, url_path, expected_file_path, headers=None):
raise SipiTestError(
"Sipi compare: pixels not identical {} {}:\n {}".format(downloaded_file_path, expected_file_path, compare_process.stdout))

def expect_status_code(self, url_path, status_code, headers=None):
def expect_status_code(self, url_path, status_code, headers=None, method='get'):
"""
Requests a file and expects to get a particular HTTP status code.
Expand All @@ -308,15 +308,13 @@ def expect_status_code(self, url_path, status_code, headers=None):
"""

sipi_url = self.make_sipi_url(url_path)
response = requests.get(sipi_url, headers=headers)
response = getattr(requests, method)(sipi_url, headers=headers)

if response.status_code != status_code:
raise SipiTestError(
"Received status code {} for URL {}, expected {} (wrote {}). Response:\n{}".format(response.status_code,
sipi_url,
status_code,
self.sipi_log_file,
response.text))
format = "Received status code {} for URL {}, expected {} (wrote {}). Response:\n{}"
raise SipiTestError(format.format(response.status_code, sipi_url, status_code, self.sipi_log_file, response.text))

return response

def get_image_info(self, url_path, headers=None):
"""
Expand Down
24 changes: 16 additions & 8 deletions test/e2e/test_02_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,21 @@
# See the GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public
# License along with Sipi. If not, see <http://www.gnu.org/licenses/>.
import filecmp
import pprint
import shutil

import pytest
from pathlib import Path
import datetime
import filecmp
import os
import os.path
import time
import datetime
import pprint
import pytest
import shutil
import subprocess
import sys

import time

# Tests basic functionality of the Sipi server.


class TestServer:
component = "The Sipi server"

Expand Down Expand Up @@ -161,6 +160,15 @@ def test_odd_file(self, manager):
downloaded_file_path = manager.download_file("/unit/{}/file".format(filename))
assert filecmp.cmp(manager.data_dir_path("knora/test_odd.odd"), downloaded_file_path)

def test_head_response_should_be_empty(self, manager):
response_json = manager.post_file("/api/upload", manager.data_dir_path("unit/lena512.tif"), "image/tiff")

http_response = manager.expect_status_code("/unit/{}/full/max/0/default.jpg".format(response_json["filename"]), 200)
process = subprocess.run(['file', '-'], input=http_response.content, capture_output=True)
assert process.stdout.startswith(b'/dev/stdin: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16')

http_response = manager.expect_status_code("/unit/{}/full/max/0/default.jpg".format(response_json["filename"]), 200, method='head')
assert http_response.text == ""

def test_mimeconsistency(self, manager):
"""upload any file and check mimetype consistency"""
Expand Down

0 comments on commit 6389403

Please sign in to comment.