79 lines
2.2 KiB
Python
79 lines
2.2 KiB
Python
"""Fetch one URL and write its content to stdout.
|
|
|
|
This version adds URL parsing (including SSL) and a Response object.
|
|
"""
|
|
|
|
import sys
|
|
import urllib.parse
|
|
|
|
from asyncio import *
|
|
|
|
|
|
class Response:
|
|
|
|
def __init__(self, verbose=True):
|
|
self.verbose = verbose
|
|
self.http_version = None # 'HTTP/1.1'
|
|
self.status = None # 200
|
|
self.reason = None # 'Ok'
|
|
self.headers = [] # [('Content-Type', 'text/html')]
|
|
|
|
@coroutine
|
|
def read(self, reader):
|
|
@coroutine
|
|
def getline():
|
|
return (yield from reader.readline()).decode('latin-1').rstrip()
|
|
status_line = yield from getline()
|
|
if self.verbose: print('<', status_line, file=sys.stderr)
|
|
self.http_version, status, self.reason = status_line.split(None, 2)
|
|
self.status = int(status)
|
|
while True:
|
|
header_line = yield from getline()
|
|
if not header_line:
|
|
break
|
|
if self.verbose: print('<', header_line, file=sys.stderr)
|
|
# TODO: Continuation lines.
|
|
key, value = header_line.split(':', 1)
|
|
self.headers.append((key, value.strip()))
|
|
if self.verbose: print(file=sys.stderr)
|
|
|
|
|
|
@coroutine
|
|
def fetch(url, verbose=True):
|
|
parts = urllib.parse.urlparse(url)
|
|
if parts.scheme == 'http':
|
|
ssl = False
|
|
elif parts.scheme == 'https':
|
|
ssl = True
|
|
else:
|
|
print('URL must use http or https.')
|
|
sys.exit(1)
|
|
port = parts.port
|
|
if port is None:
|
|
port = 443 if ssl else 80
|
|
path = parts.path or '/'
|
|
if parts.query:
|
|
path += '?' + parts.query
|
|
request = 'GET %s HTTP/1.0\r\n\r\n' % path
|
|
if verbose:
|
|
print('>', request, file=sys.stderr, end='')
|
|
r, w = yield from open_connection(parts.hostname, port, ssl=ssl)
|
|
w.write(request.encode('latin-1'))
|
|
response = Response(verbose)
|
|
yield from response.read(r)
|
|
body = yield from r.read()
|
|
return body
|
|
|
|
|
|
def main():
|
|
loop = get_event_loop()
|
|
try:
|
|
body = loop.run_until_complete(fetch(sys.argv[1], '-v' in sys.argv))
|
|
finally:
|
|
loop.close()
|
|
print(body.decode('latin-1'), end='')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|