Repository: mitmproxy/mitmproxy

Issue:
response.refresh() gives OSError on Windows
```
Navigating to secondary url:https://www.bing.com/search?q=barack+obama+quotes
Navigating to url https://www.bing.com/search?q=barack+obama+quotes iteration 25
Addon error: Traceback (most recent call last):'
Error: b'  File "C:\\Users\\task_1641995085\\build\\venv\\lib\\site-packages\\mozproxy\\backends\\mitm\\scripts\\alt-serverplayback.py", line 250, in request'
Error: b'    response.refresh()'
Error: b'  File "mitmproxy\\http.py", line 1188, in refresh'
Error: b'  File "email\\utils.py", line 147, in formatdate'
Error: b'OSError: [Errno 22] Invalid argument'
```
This error only occurs on windows. I have been able to run mitmproxy from source with our test harness, and added log statements to output the parameters being passed to `formatdate`. I've verified in a python terminal that the parameters are valid.

This did not occur until we updated from mitmproxy 5.1.1 to 7.0.4. I've checked the source code for the previous versions, and though the code has been moved around, there is no difference in the calls being made in `response.refresh()`



Discussion:
Thanks for the clear report! Could you share the concrete arguments passed to `formatdate` please?
Well we know `usegmt` is always true, but when looking for examples of `new`, I've found the issue. Most of the time it prints valid values like `1641850717.0697627`, but the next value that was printed out was negative: `-11644030337.930237`, which returns the above `OSError` when run in a python prompt.
could it be caused by this line? `delta = now - self.timestamp_start`

Unsure how else we'd end up with a negative value, or why this only occurs on Windows
Hm - this definitely is weird. Could you potentially add a
```python
print(f"{delta=} {self.timestamp_start=} {i=} {self.headers[i]=} {d=} {new=}")
```
log statement and report back what that yields for the offending flow?
`delta=1133852.30330801 self.timestamp_start=1641407457.1147604 i='last-modified' self.headers[i]='Mon, 01 Jan 1601 00:00:00 GMT' d=(1601, 1, 1, 0, 0, 0, 0, 1, -1, 0) new=-11643339747.696692`

`delta=1133830.6156322956 self.timestamp_start=1641407480.3896403 i='last-modified' self.headers[i]='Mon, 01 Jan 1601 00:00:00 GMT' d=(1601, 1, 1, 0, 0, 0, 0, 1, -1, 0) new=-11643339769.384367`

two examples of flows with negative values
every negative value has the same `last-modified` date of Jan 1, 1601

Resolving patch:
diff --git a/mitmproxy/http.py b/mitmproxy/http.py
--- a/mitmproxy/http.py
+++ b/mitmproxy/http.py
@@ -1185,7 +1185,10 @@ def refresh(self, now=None):
                 d = parsedate_tz(self.headers[i])
                 if d:
                     new = mktime_tz(d) + delta
-                    self.headers[i] = formatdate(new, usegmt=True)
+                    try:
+                        self.headers[i] = formatdate(new, usegmt=True)
+                    except OSError:  # pragma: no cover
+                        pass  # value out of bounds on Windows only (which is why we exclude it from coverage).
         c = []
         for set_cookie_header in self.headers.get_all("set-cookie"):
             try:


Test patch:
diff --git a/test/mitmproxy/test_http.py b/test/mitmproxy/test_http.py
--- a/test/mitmproxy/test_http.py
+++ b/test/mitmproxy/test_http.py
@@ -613,6 +613,11 @@ def test_refresh(self):
             m.side_effect = ValueError
             r.refresh(n)
 
+        # Test negative unixtime, which raises on at least Windows.
+        r.headers["date"] = pre = "Mon, 01 Jan 1601 00:00:00 GMT"
+        r.refresh(946681202)
+        assert r.headers["date"] == pre
+
 
 class TestHTTPFlow: