Whole file

defnull/multipart

The author described this change as fix: Allow empty segment names. It counts as a record because the check below fails on the code as it stood at e80c30a13 and passes on 6756044c9, with nothing else changed between the two runs.

Fix saved2024-09-28
Sharing licenceMIT · LICENSE
Change size+11 8

What the code was meant to do, written into the code itself as a save note

fix: Allow empty segment names

The change

407407
408408 #: List of headers as name/value pairs with normalized (Title-Case) names.
409409 headerlist: List[Tuple[str, str]]
410- #: The required 'name' option of the Content-Disposition header.
410+ #: The 'name' option of the Content-Disposition header. Always a string,
411+ #: but may be empty.
411412 name: str
412413 #: The optional 'filename' option of the Content-Disposition header.
413414 filename: Optional[str]
449450 self._size_limit = parser.max_segment_size
450451
451452 def _add_headerline(self, line: bytearray):
452- assert line and not self.name
453+ assert line and self.name is None
453454 parser = self._parser
454455
455456 if line[0] in b" \t": # Multi-line header value
477478 self.headerlist.append((name.title(), value))
478479
479480 def _close_headers(self):
480- assert not self.name and not self.complete
481+ assert self.name is None
481482
482483 cdisp = self.header("Content-Disposition")
483484 if not cdisp:
484485 raise self._fail("Missing Content-Disposition segment header")
485486 cdisp, args = parse_options_header(cdisp)
486- if cdisp != "form-data" or "name" not in args:
487- raise self._fail("Invalid Content-Disposition segment header")
488- self.name = args.get("name")
487+ if cdisp != "form-data":
488+ raise self._fail("Invalid Content-Disposition segment header: Wrong type")
489+ if "name" not in args and self._parser.strict:
490+ raise self._fail("Invalid Content-Disposition segment header: Missing name option")
491+ self.name = args.get("name", "")
489492 self.filename = args.get("filename")
490493
491494 content_type = self.header("Content-Type", "application/octet-stream")
495498 self._clen = int(self.header("Content-Length", -1))
496499
497500 def _update_size(self, bytecount: int):
498- assert self.name and not self.complete
501+ assert self.name is not None and not self.complete
499502 self.size += bytecount
500503 if self._clen >= 0 and self.size > self._clen:
501504 raise self._fail("Segment Content-Length exceeded")
503506 raise self._fail("Maximum segment size exceeded")
504507
505508 def _mark_complete(self):
506- assert self.name and not self.complete
509+ assert self.name is not None and not self.complete
507510 if self._clen >= 0 and self.size != self._clen:
508511 raise self._fail("Segment size does not match Content-Length header")
509512 self.complete = True

The check that tells the two apart

failpass·test/test_push_parser.py::TestPushParser::test_header_wrong_segment_subtype

Check file test/test_push_parser.py, taken without changes from the fix and copied onto the older code, so the exact same check runs against both versions.

Origin and history

The code before ite80c30a13ffb4183b1d90d42eec84d0ce53d0fcf
Broken version dated2024-09-28
Modulemultipart
Units changedMultipartSegment
Fingerprintae6f9c83668deb64
Checked2026-08-18 by goldset/0.1

Every field above is generated by our program. None of it is written by hand.

Other bugs found in defnull/multipart