Updated IPP Opcode/Attribute validation

We no longer validate specific attribute groupings within operations.
Instead we validate at the per-attribute level only, confirming the same
information as before, and leaving any higher-logic validating to
CUPS.

Bug: chromium:945409
Test: manually confirmed valid attribute/opcode set
Change-Id: I8c2541a8b7a1957239c2468526b75b2a77450646
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1704696
Reviewed-by: Sean Kau <skau@chromium.org>
Commit-Queue: Luum Habtemariam <luum@chromium.org>
Cr-Commit-Position: refs/heads/master@{#682451}
diff --git a/chrome/services/cups_proxy/ipp_attribute_validator.cc b/chrome/services/cups_proxy/ipp_attribute_validator.cc
index bfd4555..ccddf35 100644
--- a/chrome/services/cups_proxy/ipp_attribute_validator.cc
+++ b/chrome/services/cups_proxy/ipp_attribute_validator.cc
@@ -15,649 +15,188 @@
 
 namespace {
 
-// represents a type of a single attribute
+using ValueType = cups_ipp_parser::mojom::ValueType;
+
+// Represents the type of a single attribute.
 struct AttributeDefinition {
-  bool is_a_set;
-  cups_ipp_parser::mojom::ValueType type;
+  bool multivalued;
+
+  // Internal serialization type.
+  ValueType type;
 };
 
-// definitions of all known attributes grouped by operations
-std::map<ipp_op_t, std::map<std::string, AttributeDefinition>>
-    attributesDefinitions = {
-        {IPP_OP_CUPS_GET_PPD,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_CUPS_GET_PRINTERS,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"limit", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"printer-location",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requested-attributes",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"charset-configured",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"charset-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"color-supported",
-              {false, cups_ipp_parser::mojom::ValueType::BOOLEAN}},
-             {"compression-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"copies-default",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"document-format-default",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"document-format-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"finishings-default",
-              {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"finishings-supported",
-              {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"generated-natural-language-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"ipp-versions-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"media-default",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"media-ready", {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"media-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"natural-language-configured",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"operations-supported",
-              {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"orientation-requested-default",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"orientation-requested-supported",
-              {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"output-bin-default",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"output-bin-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"pdl-override-supported",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"print-quality-default",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"print-quality-supported",
-              {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"printer-device-id",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-info",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-location",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-make-and-model",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"sides-default",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"sides-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"uri-authentication-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"uri-security-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_CANCEL_JOB,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_CREATE_JOB,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-name", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"ipp-attribute-fidelity",
-              {false, cups_ipp_parser::mojom::ValueType::BOOLEAN}},
-             {"copies", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"finishings", {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"media", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"orientation-requested",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"output-bin", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"print-quality",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"sides", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-state", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-state-reasons",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_GET_JOB_ATTRIBUTES,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requested-attributes",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"copies", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"finishings", {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-name", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-originating-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-printer-up-time",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-state", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-state-reasons",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"media", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"orientation-requested",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"output-bin", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"print-quality",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"sides", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"time-at-completed",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"time-at-creation",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"time-at-processing",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-         }},
-        {IPP_OP_GET_JOBS,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"limit", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"requested-attributes",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"which-jobs", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"my-jobs", {false, cups_ipp_parser::mojom::ValueType::BOOLEAN}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"copies", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"finishings", {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-name", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-originating-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-printer-up-time",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-state", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-state-reasons",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"media", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"orientation-requested",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"output-bin", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"print-quality",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"sides", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"time-at-completed",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"time-at-creation",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"time-at-processing",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-         }},
-        {IPP_OP_GET_PRINTER_ATTRIBUTES,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requested-attributes",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"document-format",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"charset-configured",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"charset-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"color-supported",
-              {false, cups_ipp_parser::mojom::ValueType::BOOLEAN}},
-             {"compression-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"copies-default",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"document-format-default",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"document-format-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"finishings-default",
-              {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"finishings-supported",
-              {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"generated-natural-language-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"ipp-versions-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"media-default",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"media-ready", {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"media-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"natural-language-configured",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"operations-supported",
-              {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"orientation-requested-default",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"orientation-requested-supported",
-              {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"output-bin-default",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"output-bin-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"pages-per-minute",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"pages-per-minute-color",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"pdl-override-supported",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"print-quality-default",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"print-quality-supported",
-              {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"printer-alert",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-alert-description",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-device-id",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-info",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-is-accepting-jobs",
-              {false, cups_ipp_parser::mojom::ValueType::BOOLEAN}},
-             {"printer-location",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-make-and-model",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-more-info",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-state",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"printer-state-reasons",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-up-time",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"printer-uri-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"queued-job-count",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"sides-default",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"sides-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"uri-authentication-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"uri-security-supported",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_HOLD_JOB,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_PAUSE_PRINTER,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_PRINT_JOB,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-name", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"ipp-attribute-fidelity",
-              {false, cups_ipp_parser::mojom::ValueType::BOOLEAN}},
-             {"document-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"compression",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"document-format",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"copies", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"finishings", {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"media", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"orientation-requested",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"output-bin", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"print-quality",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"sides", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-state", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-state-reasons",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_PRINT_URI,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-name", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"ipp-attribute-fidelity",
-              {false, cups_ipp_parser::mojom::ValueType::BOOLEAN}},
-             {"document-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"compression",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"document-format",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"copies", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"finishings", {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"media", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"orientation-requested",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"output-bin", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"print-quality",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"sides", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-state", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-state-reasons",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_RELEASE_JOB,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_RESUME_PRINTER,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_SEND_DOCUMENT,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"document-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"compression",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"document-format",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-state", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-state-reasons",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_SEND_URI,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"document-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"compression",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"document-format",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-id", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-uri", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-state", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"job-state-reasons",
-              {true, cups_ipp_parser::mojom::ValueType::STRING}},
-         }},
-        {IPP_OP_VALIDATE_JOB,
-         {
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"printer-uri",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"requesting-user-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"job-name", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"ipp-attribute-fidelity",
-              {false, cups_ipp_parser::mojom::ValueType::BOOLEAN}},
-             {"document-name",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"compression",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"document-format",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"copies", {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"finishings", {true, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"media", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"orientation-requested",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"output-bin", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"print-quality",
-              {false, cups_ipp_parser::mojom::ValueType::INTEGER}},
-             {"sides", {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-charset",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"attributes-natural-language",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-             {"status-message",
-              {false, cups_ipp_parser::mojom::ValueType::STRING}},
-         }}};
+// Definitions of all known attributes.
+const std::map<std::string, AttributeDefinition> kAttributeDefinitions{
+    {"attributes-charset", {false, ValueType::STRING}},
+    {"attributes-natural-language", {false, ValueType::STRING}},
+    {"auth-info", {true, ValueType::STRING}},
+    {"auth-info-required", {true, ValueType::STRING}},
+    {"charset-configured", {false, ValueType::STRING}},
+    {"charset-supported", {true, ValueType::STRING}},
+    {"color-supported", {false, ValueType::BOOLEAN}},
+    {"compression", {false, ValueType::STRING}},
+    {"compression-supported", {true, ValueType::STRING}},
+    {"copies", {false, ValueType::INTEGER}},
+    {"copies-default", {false, ValueType::INTEGER}},
+    {"copies-supported", {true, ValueType::INTEGER}},
+    {"document-format", {false, ValueType::STRING}},
+    {"document-format-default", {false, ValueType::STRING}},
+    {"document-format-supported", {true, ValueType::STRING}},
+    {"document-name", {false, ValueType::STRING}},
+    {"finishings", {true, ValueType::INTEGER}},
+    {"finishings-default", {true, ValueType::INTEGER}},
+    {"finishings-supported", {true, ValueType::INTEGER}},
+    {"generated-natural-language-supported", {true, ValueType::STRING}},
+    {"ipp-attribute-fidelity", {false, ValueType::BOOLEAN}},
+    {"ipp-versions-supported", {true, ValueType::STRING}},
+    {"job-cancel-after", {false, ValueType::INTEGER}},
+    {"job-hold-until", {false, ValueType::STRING}},
+    {"job-hold-until-default", {false, ValueType::STRING}},
+    {"job-hold-until-supported", {true, ValueType::STRING}},
+    {"job-id", {false, ValueType::INTEGER}},
+    {"job-k-limit", {false, ValueType::INTEGER}},
+    {"job-media-progress", {false, ValueType::INTEGER}},
+    {"job-name", {false, ValueType::STRING}},
+    {"job-originating-host-name", {false, ValueType::STRING}},
+    {"job-originating-user-name", {false, ValueType::STRING}},
+    {"job-page-limit", {false, ValueType::INTEGER}},
+    {"job-printer-state-message", {false, ValueType::STRING}},
+    {"job-printer-state-reasons", {true, ValueType::STRING}},
+    {"job-printer-up-time", {false, ValueType::INTEGER}},
+    {"job-printer-uri", {false, ValueType::STRING}},
+    {"job-priority", {false, ValueType::INTEGER}},
+    {"job-priority-default", {false, ValueType::INTEGER}},
+    {"job-priority-supported", {false, ValueType::INTEGER}},
+    {"job-quota-period", {false, ValueType::INTEGER}},
+    {"job-sheets", {false, ValueType::STRING}},
+    {"job-sheets-default", {false, ValueType::STRING}},
+    {"job-sheets-supported", {true, ValueType::STRING}},
+    {"job-state", {false, ValueType::INTEGER}},
+    {"job-state-reasons", {true, ValueType::STRING}},
+    {"job-uri", {false, ValueType::STRING}},
+    {"last-document", {false, ValueType::BOOLEAN}},
+    {"limit", {false, ValueType::INTEGER}},
+    {"marker-change-time", {false, ValueType::INTEGER}},
+    {"marker-colors", {true, ValueType::STRING}},
+    {"marker-high-levels", {true, ValueType::INTEGER}},
+    {"marker-levels", {true, ValueType::INTEGER}},
+    {"marker-low-levels", {true, ValueType::INTEGER}},
+    {"marker-message", {false, ValueType::STRING}},
+    {"marker-names", {true, ValueType::STRING}},
+    {"marker-types", {true, ValueType::STRING}},
+    {"media", {false, ValueType::STRING}},
+    {"media-default", {false, ValueType::STRING}},
+    {"media-ready", {true, ValueType::STRING}},
+    {"media-supported", {true, ValueType::STRING}},
+    {"member-names", {true, ValueType::STRING}},
+    {"member-uris", {true, ValueType::STRING}},
+    {"multiple-document-handling", {false, ValueType::STRING}},
+    {"multiple-document-handling-default", {false, ValueType::STRING}},
+    {"multiple-document-handling-supported", {true, ValueType::STRING}},
+    {"my-jobs", {false, ValueType::BOOLEAN}},
+    {"natural-language-configured", {false, ValueType::STRING}},
+    {"number-up", {false, ValueType::INTEGER}},
+    {"number-up-default", {false, ValueType::INTEGER}},
+    {"number-up-supported", {true, ValueType::INTEGER}},
+    {"operations-supported", {true, ValueType::INTEGER}},
+    {"orientation-requested", {false, ValueType::INTEGER}},
+    {"orientation-requested-default", {false, ValueType::INTEGER}},
+    {"orientation-requested-supported", {true, ValueType::INTEGER}},
+    {"output-bin", {false, ValueType::STRING}},
+    {"output-bin-default", {false, ValueType::STRING}},
+    {"output-bin-supported", {true, ValueType::STRING}},
+    {"page-border", {false, ValueType::STRING}},
+    {"page-ranges", {true, ValueType::INTEGER}},
+    {"page-ranges-supported", {false, ValueType::BOOLEAN}},
+    {"pages-per-minute", {false, ValueType::INTEGER}},
+    {"pages-per-minute-color", {false, ValueType::INTEGER}},
+    {"pdl-override-supported", {false, ValueType::STRING}},
+    {"print-quality", {false, ValueType::INTEGER}},
+    {"print-quality-default", {false, ValueType::INTEGER}},
+    {"print-quality-supported", {true, ValueType::INTEGER}},
+    {"printer-alert", {true, ValueType::STRING}},
+    {"printer-alert-description", {true, ValueType::STRING}},
+    {"printer-device-id", {false, ValueType::STRING}},
+    {"printer-dns-sd-name", {false, ValueType::STRING}},
+    {"printer-id", {false, ValueType::INTEGER}},
+    {"printer-info", {false, ValueType::STRING}},
+    {"printer-is-accepting-jobs", {false, ValueType::BOOLEAN}},
+    {"printer-location", {false, ValueType::STRING}},
+    {"printer-make-and-model", {false, ValueType::STRING}},
+    {"printer-more-info", {false, ValueType::STRING}},
+    {"printer-name", {false, ValueType::STRING}},
+    {"printer-resolution", {true, ValueType::INTEGER}},
+    {"printer-resolution-default", {true, ValueType::INTEGER}},
+    {"printer-resolution-supported", {true, ValueType::INTEGER}},
+    {"printer-state", {false, ValueType::INTEGER}},
+    {"printer-state-reasons", {true, ValueType::STRING}},
+    {"printer-type", {false, ValueType::INTEGER}},
+    {"printer-type-mask", {false, ValueType::INTEGER}},
+    {"printer-up-time", {false, ValueType::INTEGER}},
+    {"printer-uri", {false, ValueType::STRING}},
+    {"printer-uri-supported", {true, ValueType::STRING}},
+    {"queued-job-count", {false, ValueType::INTEGER}},
+    {"requested-attributes", {true, ValueType::STRING}},
+    {"requesting-user-name", {false, ValueType::STRING}},
+    {"requesting-user-name-allowed", {false, ValueType::STRING}},
+    {"requesting-user-name-denied", {false, ValueType::STRING}},
+    {"sides", {false, ValueType::STRING}},
+    {"sides-default", {false, ValueType::STRING}},
+    {"sides-supported", {true, ValueType::STRING}},
+    {"status-message", {false, ValueType::STRING}},
+    {"time-at-completed", {false, ValueType::INTEGER}},
+    {"time-at-creation", {false, ValueType::INTEGER}},
+    {"time-at-processing", {false, ValueType::INTEGER}},
+    {"uri-authentication-supported", {true, ValueType::STRING}},
+    {"uri-security-supported", {true, ValueType::STRING}},
+    {"which-jobs", {false, ValueType::STRING}}};
+
+// Allowed IPP Operations.
+const std::set<ipp_op_t> kOperationIds{
+    IPP_OP_CANCEL_JOB,         IPP_OP_CREATE_JOB,
+    IPP_OP_CUPS_GET_DEFAULT,   IPP_OP_CUPS_GET_PPD,
+    IPP_OP_CUPS_GET_PRINTERS,  IPP_OP_GET_JOBS,
+    IPP_OP_GET_JOB_ATTRIBUTES, IPP_OP_GET_PRINTER_ATTRIBUTES,
+    IPP_OP_HOLD_JOB,           IPP_OP_PAUSE_PRINTER,
+    IPP_OP_PRINT_JOB,          IPP_OP_PRINT_URI,
+    IPP_OP_RELEASE_JOB,        IPP_OP_RESUME_PRINTER,
+    IPP_OP_SEND_DOCUMENT,      IPP_OP_SEND_URI,
+    IPP_OP_VALIDATE_JOB,
+};
 
 }  // namespace
 
-bool ValidateAttribute(ipp_op_t ipp_oper_id,
-                       const std::string& name,
-                       cups_ipp_parser::mojom::ValueType type,
-                       size_t values_count) {
-  auto it_oper = attributesDefinitions.find(ipp_oper_id);
-  if (it_oper == attributesDefinitions.end()) {
-    return false;
+ValidateAttributeResult ValidateAttribute(ipp_op_t ipp_oper_id,
+                                          const std::string& name,
+                                          ValueType type,
+                                          size_t values_count) {
+  // Ensure |ipp_oper_id| is an allowed operation.
+  if (!base::Contains(kOperationIds, ipp_oper_id)) {
+    return ValidateAttributeResult::kFatalError;
   }
-  auto it_attr = it_oper->second.find(name);
-  if (it_attr == it_oper->second.end()) {
-    return false;
+
+  // Ensure |name| refers to an allowed attribute.
+  auto attr_def = kAttributeDefinitions.find(name);
+  if (attr_def == kAttributeDefinitions.end()) {
+    // TODO(crbug.com/945409): Tell caller to drop this attribute.
+    return ValidateAttributeResult::kUnknownAttribute;
   }
-  if (it_attr->second.type != type) {
-    return false;
-  }
+
+  // Ensure every attribute has some value.
   if (values_count == 0) {
-    return false;
+    return ValidateAttributeResult::kFatalError;
   }
-  if (!it_attr->second.is_a_set && values_count > 1) {
-    return false;
+
+  // Ensure single-valued attributes are single-valued.
+  if (!attr_def->second.multivalued && values_count > 1) {
+    return ValidateAttributeResult::kFatalError;
   }
-  return true;
+
+  // Ensure every attribute was serialized to the correct type.
+  if (attr_def->second.type != type) {
+    return ValidateAttributeResult::kFatalError;
+  }
+  return ValidateAttributeResult::kSuccess;
 }
 
 }  // namespace cups_proxy
diff --git a/chrome/services/cups_proxy/ipp_attribute_validator.h b/chrome/services/cups_proxy/ipp_attribute_validator.h
index 0a75eab..3a236a8c 100644
--- a/chrome/services/cups_proxy/ipp_attribute_validator.h
+++ b/chrome/services/cups_proxy/ipp_attribute_validator.h
@@ -13,20 +13,29 @@
 
 namespace cups_proxy {
 
+enum ValidateAttributeResult {
+  kSuccess = 0,
+
+  // Unknown attribute name.
+  kUnknownAttribute,
+  kFatalError,
+  kMaxValue,
+};
+
 // Validates an attribute |name| of type |type| in operation |ipp_oper_id|.
 // |values_count| represents number of values in the attribute. The following
 // constraints are enforced:
 // - only operations from predefined set are accepted
 // - only attributes from predefined set are accepted
-// - an attribute must be part of given operation (request or response)
-// - a type of the attribute must match the specification
+// - serialization type of the attribute must match the specification
 // - a single-value attribute cannot have more than one value
 // - a set-of-values attribute cannot be empty
-// Returns false <=> at least one of the constraints has been violated.
-bool ValidateAttribute(ipp_op_t ipp_oper_id,
-                       const std::string& name,
-                       cups_ipp_parser::mojom::ValueType type,
-                       size_t values_count);
+// Returns kFatalError <=> at least one of the constraints has been violated.
+ValidateAttributeResult ValidateAttribute(
+    ipp_op_t ipp_oper_id,
+    const std::string& name,
+    cups_ipp_parser::mojom::ValueType type,
+    size_t values_count);
 
 }  // namespace cups_proxy
 
diff --git a/chrome/services/cups_proxy/ipp_validator.cc b/chrome/services/cups_proxy/ipp_validator.cc
index 079501e..dce9559d 100644
--- a/chrome/services/cups_proxy/ipp_validator.cc
+++ b/chrome/services/cups_proxy/ipp_validator.cc
@@ -15,6 +15,7 @@
 
 #include "base/containers/span.h"
 #include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "chrome/services/cups_proxy/ipp_attribute_validator.h"
@@ -121,6 +122,7 @@
 
 base::Optional<std::vector<ipp_converter::HttpHeader>>
 IppValidator::ValidateHttpHeaders(
+    const size_t http_content_length,
     const base::flat_map<std::string, std::string>& headers) {
   // Sane, character-set checks.
   for (const auto& header : headers) {
@@ -130,9 +132,20 @@
     }
   }
 
-  return std::vector<ipp_converter::HttpHeader>(headers.begin(), headers.end());
+  std::vector<ipp_converter::HttpHeader> ret(headers.begin(), headers.end());
+
+  // Update the ContentLength.
+  base::EraseIf(ret, [](const ipp_converter::HttpHeader& header) {
+    return header.first == "Content-Length";
+  });
+  ret.push_back({"Content-Length", base::NumberToString(http_content_length)});
+
+  return ret;
 }
 
+// Note: Since its possible to have valid IPP attributes that our
+// ipp_attribute_validator.cc is unaware of, we drop unknown attributes, rather
+// than fail the request.
 ipp_t* IppValidator::ValidateIppMessage(
     cups_ipp_parser::mojom::IppMessagePtr ipp_message) {
   printing::ScopedIppPtr ipp = printing::WrapIpp(ippNew());
@@ -161,10 +174,17 @@
       return nullptr;
     }
 
-    if (!ValidateAttribute(ipp_oper_id, attribute->name, attribute->type,
-                           num_values)) {
+    auto ret = ValidateAttribute(ipp_oper_id, attribute->name, attribute->type,
+                                 num_values);
+    if (ret == ValidateAttributeResult::kFatalError) {
       return nullptr;
     }
+    if (ret == ValidateAttributeResult::kUnknownAttribute) {
+      // We drop unknown attributes.
+      DVLOG(1) << "CupsProxy validation: dropping unknown attribute "
+               << attribute->name;
+      continue;
+    }
 
     switch (attribute->type) {
       case cups_ipp_parser::mojom::ValueType::BOOLEAN: {
@@ -275,19 +295,6 @@
     return base::nullopt;
   }
 
-  // Build request line.
-  auto request_line = ValidateHttpRequestLine(
-      to_validate->method, to_validate->endpoint, to_validate->http_version);
-  if (!request_line.has_value()) {
-    return base::nullopt;
-  }
-
-  // Build headers.
-  auto headers = ValidateHttpHeaders(to_validate->headers);
-  if (!headers.has_value()) {
-    return base::nullopt;
-  }
-
   // Build ipp message.
   // Note: Moving ipp here, to_validate->ipp no longer valid below.
   printing::ScopedIppPtr ipp =
@@ -302,6 +309,22 @@
     return base::nullopt;
   }
 
+  // Build request line.
+  auto request_line = ValidateHttpRequestLine(
+      to_validate->method, to_validate->endpoint, to_validate->http_version);
+  if (!request_line.has_value()) {
+    return base::nullopt;
+  }
+
+  // Build headers; must happen after ipp message/data since it requires the
+  // ContentLength.
+  const size_t http_content_length =
+      ippLength(ipp.get()) + to_validate->data.size();
+  auto headers = ValidateHttpHeaders(http_content_length, to_validate->headers);
+  if (!headers.has_value()) {
+    return base::nullopt;
+  }
+
   // Marshall request
   IppRequest ret;
   ret.request_line = std::move(*request_line);
diff --git a/chrome/services/cups_proxy/ipp_validator.h b/chrome/services/cups_proxy/ipp_validator.h
index 03770c7ef..7b2c1e3d 100644
--- a/chrome/services/cups_proxy/ipp_validator.h
+++ b/chrome/services/cups_proxy/ipp_validator.h
@@ -42,6 +42,7 @@
       base::StringPiece http_version);
 
   base::Optional<std::vector<ipp_converter::HttpHeader>> ValidateHttpHeaders(
+      const size_t http_content_length,
       const base::flat_map<std::string, std::string>& headers);
 
   ipp_t* ValidateIppMessage(cups_ipp_parser::mojom::IppMessagePtr ipp_message);
diff --git a/chrome/services/cups_proxy/ipp_validator_unittest.cc b/chrome/services/cups_proxy/ipp_validator_unittest.cc
index e9b528f..98ba4f9d 100644
--- a/chrome/services/cups_proxy/ipp_validator_unittest.cc
+++ b/chrome/services/cups_proxy/ipp_validator_unittest.cc
@@ -176,6 +176,26 @@
   EXPECT_TRUE(RunValidateIppRequest(request));
 }
 
+// Test that we drop unknown attributes and succeed the request.
+TEST_F(IppValidatorTest, UnknownAttribute) {
+  auto request = GetBasicIppRequest();
+
+  // Add fake attribute.
+  std::string fake_attr_name = "fake-attribute-name";
+  IppAttributePtr fake_attr =
+      BuildAttributePtr(fake_attr_name, IPP_TAG_OPERATION, IPP_TAG_TEXT);
+  fake_attr->type = ValueType::STRING;
+  fake_attr->value->set_strings({"fake_attribute_value"});
+  request->ipp->attributes.push_back(std::move(fake_attr));
+
+  auto result = RunValidateIppRequest(request);
+  ASSERT_TRUE(result);
+
+  // Ensure resulting validated IPP request doesn't contain fake_attr_name.
+  ipp_t* ipp = result->ipp.get();
+  EXPECT_FALSE(ippFindAttribute(ipp, fake_attr_name.c_str(), IPP_TAG_TEXT));
+}
+
 // TODO(crbug.com/945409): Test IPP validation.
 
 }  // namespace