--- src/lib.rs.before
+++ src/lib.rs
@@ -61,6 +61,52 @@
             .call_method1(pyo3::intern!(py, "set_result"), (value,))?;
     }
     Ok(())
+}
+
+// Built-in containers need no Python iterator allocation. Read the current
+// length at each step, preserving list mutation by user-supplied pair iterators.
+enum HeaderItems<'py> {
+    List(Bound<'py, PyList>, usize),
+    Tuple(Bound<'py, pyo3::types::PyTuple>, usize),
+    Other(Bound<'py, pyo3::types::PyIterator>),
+}
+impl<'py> HeaderItems<'py> {
+    fn new(value: &Bound<'py, PyAny>) -> PyResult<Self> {
+        if value.is_exact_instance_of::<PyList>() {
+            Ok(Self::List(value.cast::<PyList>()?.clone(), 0))
+        } else if value.is_exact_instance_of::<pyo3::types::PyTuple>() {
+            Ok(Self::Tuple(
+                value.cast::<pyo3::types::PyTuple>()?.clone(),
+                0,
+            ))
+        } else {
+            Ok(Self::Other(value.try_iter()?))
+        }
+    }
+}
+impl<'py> Iterator for HeaderItems<'py> {
+    type Item = PyResult<Bound<'py, PyAny>>;
+    fn next(&mut self) -> Option<Self::Item> {
+        match self {
+            Self::List(list, index) => {
+                if *index >= list.len() {
+                    return None;
+                }
+                let item = list.get_item(*index);
+                *index += 1;
+                Some(item)
+            }
+            Self::Tuple(tuple, index) => {
+                if *index >= tuple.len() {
+                    return None;
+                }
+                let item = tuple.get_item(*index);
+                *index += 1;
+                Some(item)
+            }
+            Self::Other(iterator) => iterator.next(),
+        }
+    }
 }
 
 fn header_pair<'py>(
@@ -786,7 +832,7 @@
             let mut has_date = false;
             let mut close = false;
             if let Some(h) = msg.get_item(pyo3::intern!(py, "headers"))? {
-                for item in h.try_iter()? {
+                for item in HeaderItems::new(&h)? {
                     let item = item?;
                     let (name, value) = header_pair(&item)?;
                     let name = name.as_bytes();
@@ -969,7 +1015,7 @@
             let mut output = Vec::new();
             let mut headers = Vec::new();
             if let Some(h) = msg.get_item(pyo3::intern!(py, "headers"))? {
-                for item in h.try_iter()? {
+                for item in HeaderItems::new(&h)? {
                     let (n, v) = header_pair(&item?)?;
                     let n = n.as_bytes().to_ascii_lowercase();
                     let v = v.as_bytes();
