Files
Scott Laglerandpeace-maker 5efe909a91 Add Type Annotations for parts of pwnlib/util (#2679)
* Add Type Annotations for parts of pwnlib/util

* fix: use Callable in pwnlib/util/lists.py

* fix: Import Errors

* fix: use getLogger in pwnlib/util/net

* feat: use collections.abc.Buffer where appropriate

* fix: remove collections.abc.Buffer to use Sequence

* add CHANGELOG.md entry

* Improve packing and fiddling types

* Introduce own `BytesLike` type instead of 3.12 Buffer

* Improve web.wget types

* Use TypedDict in util.net

Specify generics properly.

* Improve pwnlib.proc types

* Improve pwnlib.util.lists types

* Fix util.splash types

* Make TypeVars private

* Improve util.hexdump types

* Remove partial types from packing.fit/flat

Those require more work to be useful.

* Fix implicit wget return

* Fix term.text type export

* Fix js_escape return type

* Fix sh_string doctest types

* Fix usage of ssh_channel as ssh_process

We access the pid, so a plain ssh_channel is not enough.

* Improve util.lists types

* Improve packing.dd types

* Fix relying on socket.AddressFamily type at runtime

The type is only in typeshed and not the real socket module. Don't access it at runtime, only at type checking.

* Fix lists.findall with string needle

* Fix dd on two files

* Update mypy-baseline.txt

* Remove testing artifacts from mypy-baseline.txt

---------

Co-authored-by: peace-maker <[email protected]>
2026-08-16 19:45:40 +02:00

80 lines
2.5 KiB
Python

import os
import tempfile
from typing import Any
from pwnlib.log import getLogger
from pwnlib.tubes.buffer import Buffer
from pwnlib.util.misc import size
log = getLogger(__name__)
def wget(url: str | bytes, save: str | bytes | bool = False, timeout: float | tuple[float, float] | None = 5.0, **kwargs: Any) -> bytes | None:
r"""wget(url, save=None, timeout=5) -> str
Downloads a file via HTTP/HTTPS.
Arguments:
url (str): URL to download
save (str or bool): Name to save as. Any truthy value
will auto-generate a name based on the URL.
timeout (float, tuple): Timeout, in seconds. Can be a single value for both connect and read,
or a tuple of (connect, read). Set to None to disable timeouts.
Example:
>>> url = 'https://httpbingo.org/robots.txt'
>>> result = wget(url, timeout=60)
>>> result
b'User-agent: *\nDisallow: /deny\n'
>>> filename = tempfile.mktemp()
>>> result2 = wget(url, filename, timeout=60)
>>> result == open(filename, 'rb').read()
True
"""
import requests
with log.progress("Downloading %r" % url, rate=0.1) as w:
w.status("Making request...")
response = requests.get(url, stream=True, timeout=timeout, **kwargs)
if not response.ok:
w.failure("Got code %s" % response.status_code)
return None
total_size = int(response.headers.get('content-length',0))
w.status('0 / %s' % size(total_size))
# Find out the next largest size we can represent as
chunk_size = 1
while chunk_size < (total_size/10):
chunk_size *= 1000
# Count chunks as they're received
buf = Buffer()
# Loop until we have all of the data
for chunk in response.iter_content(chunk_size = 2**10):
buf.add(chunk)
if total_size:
w.status('%s / %s' % (size(buf.size), size(total_size)))
else:
w.status('%s' % size(buf.size))
total_data = buf.get()
# Save to the target file if provided
if save:
if not isinstance(save, (bytes, str)):
save = os.path.basename(url)
save = save or tempfile.NamedTemporaryFile(dir='.', delete=False).name
with open(save,'wb+') as f:
f.write(total_data)
w.success('Saved %r (%s)' % (f.name, size(total_data)))
else:
w.success('%s' % size(total_data))
return total_data