diff options
Diffstat (limited to 'netlib')
-rw-r--r-- | netlib/http/__init__.py | 2 | ||||
-rw-r--r-- | netlib/http/authentication.py (renamed from netlib/http_auth.py) | 5 | ||||
-rw-r--r-- | netlib/http/cookies.py (renamed from netlib/http_cookies.py) | 8 | ||||
-rw-r--r-- | netlib/http/exceptions.py | 9 | ||||
-rw-r--r-- | netlib/http/http1/__init__.py | 1 | ||||
-rw-r--r-- | netlib/http/http1/protocol.py (renamed from netlib/http.py) | 95 | ||||
-rw-r--r-- | netlib/http/http2/__init__.py (renamed from netlib/http2/__init__.py) | 0 | ||||
-rw-r--r-- | netlib/http/http2/frame.py (renamed from netlib/http2/frame.py) | 0 | ||||
-rw-r--r-- | netlib/http/http2/protocol.py (renamed from netlib/http2/protocol.py) | 0 | ||||
-rw-r--r-- | netlib/http/semantics.py | 94 | ||||
-rw-r--r-- | netlib/http/status_codes.py (renamed from netlib/http_status.py) | 0 | ||||
-rw-r--r-- | netlib/http/user_agents.py (renamed from netlib/http_uastrings.py) | 0 | ||||
-rw-r--r-- | netlib/http_semantics.py | 23 | ||||
-rw-r--r-- | netlib/websockets/frame.py | 2 | ||||
-rw-r--r-- | netlib/websockets/protocol.py | 2 |
15 files changed, 130 insertions, 111 deletions
diff --git a/netlib/http/__init__.py b/netlib/http/__init__.py new file mode 100644 index 00000000..9b4b0e6b --- /dev/null +++ b/netlib/http/__init__.py @@ -0,0 +1,2 @@ +from exceptions import * +from semantics import * diff --git a/netlib/http_auth.py b/netlib/http/authentication.py index adab4aed..26e3c2c4 100644 --- a/netlib/http_auth.py +++ b/netlib/http/authentication.py @@ -1,6 +1,7 @@ from __future__ import (absolute_import, print_function, division) from argparse import Action, ArgumentTypeError -from . import http + +from .. import http class NullProxyAuth(object): @@ -46,7 +47,7 @@ class BasicProxyAuth(NullProxyAuth): auth_value = headers.get(self.AUTH_HEADER, []) if not auth_value: return False - parts = http.parse_http_basic_auth(auth_value[0]) + parts = http.http1.parse_http_basic_auth(auth_value[0]) if not parts: return False scheme, username, password = parts diff --git a/netlib/http_cookies.py b/netlib/http/cookies.py index e91ee5c0..b77e3503 100644 --- a/netlib/http_cookies.py +++ b/netlib/http/cookies.py @@ -1,3 +1,7 @@ +import re + +from .. import odict + """ A flexible module for cookie parsing and manipulation. @@ -22,10 +26,6 @@ variants. Serialization follows RFC6265. # TODO # - Disallow LHS-only Cookie values -import re - -import odict - def _read_until(s, start, term): """ diff --git a/netlib/http/exceptions.py b/netlib/http/exceptions.py new file mode 100644 index 00000000..8a2bbebc --- /dev/null +++ b/netlib/http/exceptions.py @@ -0,0 +1,9 @@ +class HttpError(Exception): + + def __init__(self, code, message): + super(HttpError, self).__init__(message) + self.code = code + + +class HttpErrorConnClosed(HttpError): + pass diff --git a/netlib/http/http1/__init__.py b/netlib/http/http1/__init__.py new file mode 100644 index 00000000..6b5043af --- /dev/null +++ b/netlib/http/http1/__init__.py @@ -0,0 +1 @@ +from protocol import * diff --git a/netlib/http.py b/netlib/http/http1/protocol.py index 073e9a3f..0f7a0bd3 100644 --- a/netlib/http.py +++ b/netlib/http/http1/protocol.py @@ -1,37 +1,13 @@ from __future__ import (absolute_import, print_function, division) +import binascii import collections import string -import urlparse -import binascii import sys -from . import odict, utils, tcp, http_semantics, http_status - - -class HttpError(Exception): - - def __init__(self, code, message): - super(HttpError, self).__init__(message) - self.code = code - - -class HttpErrorConnClosed(HttpError): - pass - - -def _is_valid_port(port): - if not 0 <= port <= 65535: - return False - return True - +import urlparse -def _is_valid_host(host): - try: - host.decode("idna") - except ValueError: - return False - if "\0" in host: - return None - return True +from netlib import odict, utils, tcp, http +from .. import status_codes +from ..exceptions import * def get_request_line(fp): @@ -44,51 +20,6 @@ def get_request_line(fp): line = fp.readline() return line - -def parse_url(url): - """ - Returns a (scheme, host, port, path) tuple, or None on error. - - Checks that: - port is an integer 0-65535 - host is a valid IDNA-encoded hostname with no null-bytes - path is valid ASCII - """ - try: - scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) - except ValueError: - return None - if not scheme: - return None - if '@' in netloc: - # FIXME: Consider what to do with the discarded credentials here Most - # probably we should extend the signature to return these as a separate - # value. - _, netloc = string.rsplit(netloc, '@', maxsplit=1) - if ':' in netloc: - host, port = string.rsplit(netloc, ':', maxsplit=1) - try: - port = int(port) - except ValueError: - return None - else: - host = netloc - if scheme == "https": - port = 443 - else: - port = 80 - path = urlparse.urlunparse(('', '', path, params, query, fragment)) - if not path.startswith("/"): - path = "/" + path - if not _is_valid_host(host): - return None - if not utils.isascii(path): - return None - if not _is_valid_port(port): - return None - return scheme, host, port, path - - def read_headers(fp): """ Read a set of headers from a file pointer. Stop once a blank line is @@ -193,6 +124,7 @@ def parse_http_protocol(s): def parse_http_basic_auth(s): + # TODO: check if this is HTTP/1 only - otherwise move it to netlib.http.semantics words = s.split() if len(words) != 2: return None @@ -208,6 +140,7 @@ def parse_http_basic_auth(s): def assemble_http_basic_auth(scheme, username, password): + # TODO: check if this is HTTP/1 only - otherwise move it to netlib.http.semantics v = binascii.b2a_base64(username + ":" + password) return scheme + " " + v @@ -245,9 +178,9 @@ def parse_init_connect(line): port = int(port) except ValueError: return None - if not _is_valid_port(port): + if not http.is_valid_port(port): return None - if not _is_valid_host(host): + if not http.is_valid_host(host): return None return host, port, httpversion @@ -258,7 +191,7 @@ def parse_init_proxy(line): return None method, url, httpversion = v - parts = parse_url(url) + parts = http.parse_url(url) if not parts: return None scheme, host, port, path = parts @@ -421,6 +354,7 @@ def expected_http_body_size(headers, is_request, request_method, response_code): return -1 +# TODO: make this a regular class - just like Response Request = collections.namedtuple( "Request", [ @@ -529,7 +463,7 @@ def read_request(rfile, include_body=True, body_size_limit=None, wfile=None): def read_response(rfile, request_method, body_size_limit, include_body=True): """ - Return an (httpversion, code, msg, headers, content) tuple. + Returns an http.Response By default, both response header and body are read. If include_body=False is specified, content may be one of the @@ -538,6 +472,7 @@ def read_response(rfile, request_method, body_size_limit, include_body=True): - "", if the response must not have a response body (e.g. it's a response to a HEAD request) """ + line = rfile.readline() # Possible leftover from previous message if line == "\r\n" or line == "\n": @@ -568,7 +503,7 @@ def read_response(rfile, request_method, body_size_limit, include_body=True): # if include_body==False then a None content means the body should be # read separately content = None - return http_semantics.Response(httpversion, code, msg, headers, content) + return http.Response(httpversion, code, msg, headers, content) def request_preamble(method, resource, http_major="1", http_minor="1"): @@ -579,5 +514,5 @@ def request_preamble(method, resource, http_major="1", http_minor="1"): def response_preamble(code, message=None, http_major="1", http_minor="1"): if message is None: - message = http_status.RESPONSES.get(code) + message = status_codes.RESPONSES.get(code) return 'HTTP/%s.%s %s %s' % (http_major, http_minor, code, message) diff --git a/netlib/http2/__init__.py b/netlib/http/http2/__init__.py index 5acf7696..5acf7696 100644 --- a/netlib/http2/__init__.py +++ b/netlib/http/http2/__init__.py diff --git a/netlib/http2/frame.py b/netlib/http/http2/frame.py index f7e60471..f7e60471 100644 --- a/netlib/http2/frame.py +++ b/netlib/http/http2/frame.py diff --git a/netlib/http2/protocol.py b/netlib/http/http2/protocol.py index 8e5f5429..8e5f5429 100644 --- a/netlib/http2/protocol.py +++ b/netlib/http/http2/protocol.py diff --git a/netlib/http/semantics.py b/netlib/http/semantics.py new file mode 100644 index 00000000..e7e84fe3 --- /dev/null +++ b/netlib/http/semantics.py @@ -0,0 +1,94 @@ +from __future__ import (absolute_import, print_function, division) +import binascii +import collections +import string +import sys +import urlparse + +from .. import utils + +class Response(object): + + def __init__( + self, + httpversion, + status_code, + msg, + headers, + content, + sslinfo=None, + ): + self.httpversion = httpversion + self.status_code = status_code + self.msg = msg + self.headers = headers + self.content = content + self.sslinfo = sslinfo + + def __eq__(self, other): + return self.__dict__ == other.__dict__ + + def __repr__(self): + return "Response(%s - %s)" % (self.status_code, self.msg) + + + +def is_valid_port(port): + if not 0 <= port <= 65535: + return False + return True + + +def is_valid_host(host): + try: + host.decode("idna") + except ValueError: + return False + if "\0" in host: + return None + return True + + + +def parse_url(url): + """ + Returns a (scheme, host, port, path) tuple, or None on error. + + Checks that: + port is an integer 0-65535 + host is a valid IDNA-encoded hostname with no null-bytes + path is valid ASCII + """ + try: + scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) + except ValueError: + return None + if not scheme: + return None + if '@' in netloc: + # FIXME: Consider what to do with the discarded credentials here Most + # probably we should extend the signature to return these as a separate + # value. + _, netloc = string.rsplit(netloc, '@', maxsplit=1) + if ':' in netloc: + host, port = string.rsplit(netloc, ':', maxsplit=1) + try: + port = int(port) + except ValueError: + return None + else: + host = netloc + if scheme == "https": + port = 443 + else: + port = 80 + path = urlparse.urlunparse(('', '', path, params, query, fragment)) + if not path.startswith("/"): + path = "/" + path + if not is_valid_host(host): + return None + if not utils.isascii(path): + return None + if not is_valid_port(port): + return None + return scheme, host, port, path diff --git a/netlib/http_status.py b/netlib/http/status_codes.py index dc09f465..dc09f465 100644 --- a/netlib/http_status.py +++ b/netlib/http/status_codes.py diff --git a/netlib/http_uastrings.py b/netlib/http/user_agents.py index e8681908..e8681908 100644 --- a/netlib/http_uastrings.py +++ b/netlib/http/user_agents.py diff --git a/netlib/http_semantics.py b/netlib/http_semantics.py deleted file mode 100644 index e8313e3c..00000000 --- a/netlib/http_semantics.py +++ /dev/null @@ -1,23 +0,0 @@ -class Response(object): - - def __init__( - self, - httpversion, - status_code, - msg, - headers, - content, - sslinfo=None, - ): - self.httpversion = httpversion - self.status_code = status_code - self.msg = msg - self.headers = headers - self.content = content - self.sslinfo = sslinfo - - def __eq__(self, other): - return self.__dict__ == other.__dict__ - - def __repr__(self): - return "Response(%s - %s)" % (self.status_code, self.msg) diff --git a/netlib/websockets/frame.py b/netlib/websockets/frame.py index d41059fa..49d8ee10 100644 --- a/netlib/websockets/frame.py +++ b/netlib/websockets/frame.py @@ -6,7 +6,7 @@ import struct import io from .protocol import Masker -from .. import utils, odict, tcp +from netlib import utils, odict, tcp DEFAULT = object() diff --git a/netlib/websockets/protocol.py b/netlib/websockets/protocol.py index dcab53fb..29b4db3d 100644 --- a/netlib/websockets/protocol.py +++ b/netlib/websockets/protocol.py @@ -5,7 +5,7 @@ import os import struct import io -from .. import utils, odict, tcp +from netlib import utils, odict, tcp # Colleciton of utility functions that implement small portions of the RFC6455 # WebSockets Protocol Useful for building WebSocket clients and servers. |