Skip to content

Commit

Permalink
Enhance WITH-[ALL-]CONTENT support to validate IPP, PDF, and .strings…
Browse files Browse the repository at this point in the history
… files (Issue #87)

Strip HTML target ("...#target") from URIs when doing validation.

Update man pages.

Add resource validation test file.
  • Loading branch information
michaelrsweet committed Sep 12, 2024
1 parent 15e3e29 commit 9362942
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 16 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ libcups v3.0rc1 (TBD)
- Updated the various tool man pages, usage output, and examples.
- Updated `ippCreateRequestedArray` for the Get-Documents and
Get-Output-Device-Attributes operations.
- Updated `ipptool` to validate IPP, PDF, and .strings files using the
"WITH-[ALL-]CONTENT" predicate (Issue #87)
- Now use installed PDFio library, if available.
- Now use NotoSansMono font for `ipptransform` text conversions.
- Brought back IPP/2.x and related conformance test files (Issue #85)
Expand Down
3 changes: 2 additions & 1 deletion examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ TESTFILES = \
rfc3995-3996.test \
rfc3998.test \
set-attrs-hold.test \
validate-job.test
validate-job.test \
validate-resources.test


#
Expand Down
29 changes: 29 additions & 0 deletions examples/validate-resources.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Validate printer resources
{
NAME "Validate Printer Resources"
OPERATION Get-Printer-Attributes
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
ATTR language attributes-natural-language en
ATTR uri printer-uri $uri
ATTR name requesting-user-name $user

STATUS successful-ok

EXPECT ?printer-charge-info-uri OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1 WITH-CONTENT valid

EXPECT printer-icc-profiles OF-TYPE collection IN-GROUP printer-attributes-tag DEFINE-MATCH PRINTER_HAS_ICC_PROFILES
EXPECT printer-icc-profiles/profile-uri OF-TYPE uri COUNT 1 WITH-CONTENT valid IF-DEFINED PRINTER_HAS_ICC_PROFILES

EXPECT ?printer-icons OF-TYPE uri IN-GROUP printer-attributes-tag WITH-ALL-CONTENT valid-icon

EXPECT ?printer-more-info OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1 WITH-CONTENT valid

EXPECT ?printer-more-info-manufacturer OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1 WITH-CONTENT valid

EXPECT ?printer-privacy-policy-uri OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1 WITH-CONTENT valid

EXPECT ?printer-static-resource-directory-uri OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1 WITH-CONTENT valid

EXPECT ?printer-strings-uri OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1 WITH-CONTENT valid
}
21 changes: 18 additions & 3 deletions man/ipptool.1
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
.\"
.\" ipptool man page.
.\"
.\" Copyright © 2021-2023 by OpenPrinting.
.\" Copyright © 2021-2024 by OpenPrinting.
.\" Copyright © 2010-2019 by Apple Inc.
.\"
.\" Licensed under Apache License v2.0. See the file "LICENSE" for more
.\" information.
.\"
.TH ipptool 1 "CUPS" "2023-11-22" "OpenPrinting"
.TH ipptool 1 "CUPS" "2024-09-12" "OpenPrinting"
.SH NAME
ipptool \- perform internet printing protocol requests
.SH SYNOPSIS
Expand Down Expand Up @@ -227,6 +227,8 @@ The following standard test files are available:
identify\-printer\-display.test - Identify a printer via the display
ipp\-1.1.test - Run IPP/1.1 conformance tests
ipp\-2.0.test - Run IPP/2.0 conformance tests
ipp\-2.1.test - Run IPP/2.1 conformance tests
ipp\-2.2.test - Run IPP/2.2 conformance tests
print\-job.test - Print a file
print\-job\-and\-wait.test - Print a file and wait for completion
print\-job\-deflate.test - Print a file with deflate compression
Expand All @@ -239,8 +241,21 @@ The following standard test files are available:
print\-job\-password.test - Print a file with a password/PIN
print\-job\-raster.test - Print a generated raster file
print\-uri.test - Print a URI/URL
pwg5100.1.test - Test PWG 5100.1 (Finishings) conformance
pwg5100.2.test - Test PWG 5100.2 (output-bin) conformance
pwg5100.3.test - Test PWG 5100.3 (Production) conformance
pwg5100.5.test - Test PWG 5100.5 (Document Object) conformance
pwg5100.6.test - Test PWG 5100.6 (Page Overrides) conformance
pwg5100.7.test - Test PWG 5100.7 (Job Extensions) conformance
pwg5100.8.test - Test PWG 5100.8 (-actuals) conformance
pwg5100.9.test - Test PWG 5100.9 (Alerts) conformance
pwg5100.11.test - Test PWG 5100.11 (Enterprise) conformance
rfc3380.test - Test RFC 3380 (Job and Printer Set) conformance
rfc3995-3996.test - Test RFC 3995/3996 (Notifications) conformance
rfc3998.test - Test RFC 3998 (Admin) conformance
set\-attrs\-hold.test - Test setting job-hold-until to hold a job
validate\-job.test - Validate a job ticket
validate\-resources.test - Validate printer resource files and web pages
.fi
.PP
The following standard document files are available:
Expand Down Expand Up @@ -287,4 +302,4 @@ IANA IPP Registry (https://www.iana.org/assignments/ipp\-registrations),
PWG Internet Printing Protocol Workgroup (https://www.pwg.org/ipp),
RFC 8011 (https://datatracker.ietf.org/doc/html/rfc8011)
.SH COPYRIGHT
Copyright \[co] 2021-2023 by OpenPrinting.
Copyright \[co] 2021-2024 by OpenPrinting.
9 changes: 6 additions & 3 deletions man/ipptoolfile.5
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
.\"
.\" ipptoolfile man page.
.\"
.\" Copyright © 2021-2023 by OpenPrinting.
.\" Copyright © 2021-2024 by OpenPrinting.
.\" Copyright © 2010-2021 by Apple Inc.
.\"
.\" Licensed under Apache License v2.0. See the file "LICENSE" for more
.\" information.
.\"
.TH ipptoolfile 5 "CUPS" "2023-11-17" "OpenPrinting"
.TH ipptoolfile 5 "CUPS" "2024-09-12" "OpenPrinting"
.SH NAME
ipptoolfile \- ipptool file format
.SH DESCRIPTION
Expand Down Expand Up @@ -352,6 +352,9 @@ A "http" or "https" URI must respond to a GET request while a "ipp" or "ipps" UR
.TP 5
\fBWITH\-CONTENT valid\fR
Requires that all "http" and "https" URI values be accessible and provide valid content.
Currently
.B ipptool
is able to validate CSS, HTML, ICC, IPP, JPEG, PDF, PNG, and Apple .strings files.
.TP 5
\fBWITH\-ALL\-CONTENT valid-icon\fR
.TP 5
Expand Down Expand Up @@ -886,4 +889,4 @@ PWG 5101.1-2023: PWG Media Standardized Names v2.1 (https://ftp.pwg.org/pub/pwg/
.PP
RFC 8011 (https://datatracker.ietf.org/doc/html/rfc8011)
.SH COPYRIGHT
Copyright \[co] 2021-2023 by OpenPrinting.
Copyright \[co] 2021-2024 by OpenPrinting.
2 changes: 1 addition & 1 deletion pdfio
4 changes: 2 additions & 2 deletions tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ ippfind-static: ippfind.o ../cups/$(LIBCUPS_STATIC)

ipptool: ipptool.o ../cups/$(LIBCUPS) ipptool-static
echo Linking $@...
$(CC) $(LDFLAGS) $(OPTIM) -o $@ ipptool.o $(LINKCUPS) $(LIBS)
$(CC) $(LDFLAGS) $(OPTIM) -o $@ ipptool.o $(LINKCUPS) $(XFORMLIBS) $(LIBS)
$(CODE_SIGN) $(CSFLAGS) $@


Expand All @@ -182,7 +182,7 @@ ipptool: ipptool.o ../cups/$(LIBCUPS) ipptool-static

ipptool-static: ipptool.o ../cups/$(LIBCUPS_STATIC)
echo Linking $@...
$(CC) $(LDFLAGS) $(OPTIM) -o $@ ipptool.o ../cups/$(LIBCUPS_STATIC) $(LIBS)
$(CC) $(LDFLAGS) $(OPTIM) -o $@ ipptool.o ../cups/$(LIBCUPS_STATIC) $(XFORMLIBS) $(LIBS)
$(CODE_SIGN) $(CSFLAGS) $@


Expand Down
91 changes: 85 additions & 6 deletions tools/ipptool.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// ipptool command for CUPS.
//
// Copyright © 2021-2023 by OpenPrinting.
// Copyright © 2021-2024 by OpenPrinting.
// Copyright © 2020 by The Printer Working Group.
// Copyright © 2007-2021 by Apple Inc.
// Copyright © 1997-2007 by Easy Software Products.
Expand All @@ -26,6 +26,7 @@
#ifndef O_BINARY
# define O_BINARY 0
#endif // !O_BINARY
#include <pdfio.h>


//
Expand Down Expand Up @@ -238,6 +239,7 @@ static bool parse_generate_file(ipp_file_t *f, ipptool_test_t *data);
static bool parse_monitor_printer_state(ipp_file_t *f, ipptool_test_t *data);
static const char *password_cb(const char *prompt, http_t *http, const char *method, const char *resource, void *user_data);
static void pause_message(const char *message);
static bool pdf_error_cb(pdfio_file_t *pdf, const char *message, cups_array_t *errors);
static void print_attr(cups_file_t *outfile, ipptool_output_t output, ipp_attribute_t *attr, ipp_tag_t *group);
static ipp_attribute_t *print_csv(ipptool_test_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths);
static void print_fatal_error(ipptool_test_t *data, const char *s, ...) _CUPS_FORMAT(2, 3);
Expand Down Expand Up @@ -4121,6 +4123,23 @@ pause_message(const char *message) // I - Message
}


//
// 'pdf_error_cb()' - PDFio error callback.
//

static bool // O - `false` to stop loading
pdf_error_cb(pdfio_file_t *pdf, // I - PDF file
const char *message, // I - Error message
cups_array_t *errors) // I - Array of error messages
{
(void)pdf;

add_stringf(errors, "Unable to open PDF file: %s", message);

return (false);
}


//
// 'print_attr()' - Print an attribute on the screen.
//
Expand Down Expand Up @@ -6700,7 +6719,8 @@ with_content(
char scheme[256], // Scheme
userpass[256], // Username:password (not used)
host[256], // Hostname
resource[256]; // Resource path
resource[256], // Resource path
*resptr; // Pointer into resource
int port; // Port number
http_encryption_t encryption; // Encryption mode
http_uri_status_t uri_status; // URI decoding status
Expand All @@ -6720,6 +6740,9 @@ with_content(
continue;
}

if ((resptr = strchr(resource, '#')) != NULL)
*resptr = '\0'; // Strip HTML target ("...#target")

if (strcmp(scheme, "http") && strcmp(scheme, "https") && strcmp(scheme, "ipp") && strcmp(scheme, "ipps"))
{
add_stringf(errors, "Unsupported URI scheme for '%s'.", uri);
Expand Down Expand Up @@ -6789,7 +6812,7 @@ with_content(

if (status != HTTP_STATUS_OK)
{
add_stringf(errors, "Got unexpected status %d for HEAD request to '%s'.", (int)status, uri);
add_stringf(errors, "Got unexpected status %d for GET request to '%s'.", (int)status, uri);
ret = false;
goto get_done;
}
Expand Down Expand Up @@ -6833,14 +6856,70 @@ with_content(
}
else if (!_cups_strcasecmp(content_type, "image/jpeg") || !_cups_strcasecmp(content_type, "image/png"))
{
// Validate image content
if (!valid_image(filename, &width, &height, &depth))
{
add_stringf(errors, "Unable to load image '%s'.", uri);
add_stringf(errors, "Unable to open image '%s'.", uri);
ret = false;
goto get_done;
}
}
else if (!_cups_strcasecmp(content_type, "application/pdf") || !_cups_strcasecmp(content_type, "application/ipp") || !_cups_strcasecmp(content_type, "application/vnd.iccprofile") || !_cups_strcasecmp(content_type, "text/css") || !_cups_strcasecmp(content_type, "text/html") || !_cups_strcasecmp(content_type, "text/strings"))
else if (!_cups_strcasecmp(content_type, "text/strings"))
{
// Validate .strings content...
cups_lang_t *lang; // Temporary language

if ((lang = cupsLangFind("zz")) == NULL)
{
add_stringf(errors, "Unable to validate '%s'.", uri);
ret = false;
goto get_done;
}

if (!cupsLangLoadStrings(lang, filename, /*strings*/NULL))
{
add_stringf(errors, "Unable to open '%s': %s", uri, cupsGetErrorString());
ret = false;
goto get_done;
}
}
else if (!_cups_strcasecmp(content_type, "application/pdf"))
{
// Validate PDF content...
pdfio_file_t *pdf; // PDF file

if ((pdf = pdfioFileOpen(filename, /*password_cb*/NULL, /*password_data*/NULL, (pdfio_error_cb_t)pdf_error_cb, errors)) == NULL)
{
ret = false;
goto get_done;
}

pdfioFileClose(pdf);
}
else if (!_cups_strcasecmp(content_type, "application/ipp"))
{
ipp_t *ipp = ippNew(); // IPP message

if ((fd = open(filename, O_RDONLY | O_BINARY)) < 0)
{
add_stringf(errors, "Unable to open '%s': %s", uri, strerror(errno));
ippDelete(ipp);
ret = false;
goto get_done;
}
else if (ippReadFile(fd, ipp) != IPP_STATE_DATA)
{
add_stringf(errors, "Unable to read '%s': %s", uri, cupsGetErrorString());
ippDelete(ipp);
close(fd);
ret = false;
goto get_done;
}

ippDelete(ipp);
close(fd);
}
else if (!_cups_strcasecmp(content_type, "application/vnd.iccprofile") || !_cups_strcasecmp(content_type, "text/css") || !_cups_strcasecmp(content_type, "text/html") || !_cups_strncasecmp(content_type, "text/html;", 10))
{
// Just require these files to be non-empty for now, might add more checks in the future...
if (fileinfo.st_size == 0)
Expand All @@ -6852,7 +6931,7 @@ with_content(
}
else
{
add_stringf(errors, "Got unexpected Content-Type '%s' for HEAD request to '%s'.", content_type, uri);
add_stringf(errors, "Got unexpected Content-Type '%s' for GET request to '%s'.", content_type, uri);
ret = false;
goto get_done;
}
Expand Down

0 comments on commit 9362942

Please sign in to comment.