Skip to content
This repository was archived by the owner on Jan 13, 2021. It is now read-only.

Commit e7ce870

Browse files
committed
Merge pull request #172 from fredthomsen/validate_ipv6_support
Validate ipv6 support
2 parents eb57b92 + e8dd399 commit e7ce870

File tree

18 files changed

+1285
-25
lines changed

18 files changed

+1285
-25
lines changed

CONTRIBUTORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ In chronological order:
3737

3838
- Added support for upgrade of plaintext HTTP/1.1 to plaintext HTTP/2.
3939
- Added proxy support.
40+
- Improved IPv6 support.

NOTICES

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,19 @@ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2020
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2121
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2222
DEALINGS IN THE SOFTWARE.
23+
24+
rfc3986:
25+
26+
Copyright 2014 Ian Cordasco, Rackspace
27+
28+
Licensed under the Apache License, Version 2.0 (the "License");
29+
you may not use this file except in compliance with the License.
30+
You may obtain a copy of the License at
31+
32+
http://www.apache.org/licenses/LICENSE-2.0
33+
34+
Unless required by applicable law or agreed to in writing, software
35+
distributed under the License is distributed on an "AS IS" BASIS,
36+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
37+
See the License for the specific language governing permissions and
38+
limitations under the License.

hyper/cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from hyper import HTTPConnection, HTTP20Connection
1818
from hyper import __version__
1919
from hyper.compat import is_py2, urlencode, urlsplit, write_to_stdout
20+
from hyper.common.util import to_host_port_tuple
2021

2122

2223
log = logging.getLogger('hyper')
@@ -113,8 +114,7 @@ def make_troubleshooting_argument(parser):
113114
def set_url_info(args):
114115
def split_host_and_port(hostname):
115116
if ':' in hostname:
116-
host, port = hostname.split(':')
117-
return host, int(port)
117+
return to_host_port_tuple(hostname, default_port=443)
118118
return hostname, None
119119

120120
class UrlInfo(object):

hyper/common/util.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
General utility functions for use with hyper.
77
"""
88
from hyper.compat import unicode, bytes, imap
9+
from ..packages.rfc3986.uri import URIReference
10+
import re
911

1012
def to_bytestring(element):
1113
"""
@@ -25,3 +27,24 @@ def to_bytestring_tuple(*x):
2527
tuple. Uses ``to_bytestring``.
2628
"""
2729
return tuple(imap(to_bytestring, x))
30+
31+
def to_host_port_tuple(host_port_str, default_port=80):
32+
"""
33+
Converts the given string containing a host and possibly a port
34+
to a tuple.
35+
"""
36+
uri = URIReference(
37+
scheme=None,
38+
authority=host_port_str,
39+
path=None,
40+
query=None,
41+
fragment=None
42+
)
43+
44+
host = uri.host.strip('[]')
45+
if not uri.port:
46+
port = default_port
47+
else:
48+
port = int(uri.port)
49+
50+
return (host, port)

hyper/http11/connection.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from ..common.bufsocket import BufferedSocket
1616
from ..common.exceptions import TLSUpgrade, HTTPUpgrade
1717
from ..common.headers import HTTPHeaderMap
18-
from ..common.util import to_bytestring
18+
from ..common.util import to_bytestring, to_host_port_tuple
1919
from ..compat import bytes
2020

2121
from ..packages.hyperframe.frame import SettingsFrame
@@ -56,11 +56,7 @@ class HTTP11Connection(object):
5656
def __init__(self, host, port=None, secure=None, ssl_context=None,
5757
proxy_host=None, proxy_port=None, **kwargs):
5858
if port is None:
59-
try:
60-
self.host, self.port = host.split(':')
61-
self.port = int(self.port)
62-
except ValueError:
63-
self.host, self.port = host, 80
59+
self.host, self.port = to_host_port_tuple(host, default_port=80)
6460
else:
6561
self.host, self.port = host, port
6662

@@ -83,12 +79,7 @@ def __init__(self, host, port=None, secure=None, ssl_context=None,
8379
# Setup proxy details if applicable.
8480
if proxy_host:
8581
if proxy_port is None:
86-
try:
87-
self.proxy_host, self.proxy_port = proxy_host.split(':')
88-
except ValueError:
89-
self.proxy_host, self.proxy_port = proxy_host, 8080
90-
else:
91-
self.proxy_port = int(self.proxy_port)
82+
self.proxy_host, self.proxy_port = to_host_port_tuple(proxy_host, default_port=8080)
9283
else:
9384
self.proxy_host, self.proxy_port = proxy_host, proxy_port
9485
else:

hyper/http20/connection.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from ..common.exceptions import ConnectionResetError
1010
from ..common.bufsocket import BufferedSocket
1111
from ..common.headers import HTTPHeaderMap
12+
from ..common.util import to_host_port_tuple
1213
from ..packages.hyperframe.frame import (
1314
FRAMES, DataFrame, HeadersFrame, PushPromiseFrame, RstStreamFrame,
1415
SettingsFrame, Frame, WindowUpdateFrame, GoAwayFrame, PingFrame,
@@ -67,11 +68,7 @@ def __init__(self, host, port=None, secure=None, window_manager=None, enable_pus
6768
Creates an HTTP/2 connection to a specific server.
6869
"""
6970
if port is None:
70-
try:
71-
self.host, self.port = host.split(':')
72-
self.port = int(self.port)
73-
except ValueError:
74-
self.host, self.port = host, 443
71+
self.host, self.port = to_host_port_tuple(host, default_port=443)
7572
else:
7673
self.host, self.port = host, port
7774

@@ -88,12 +85,7 @@ def __init__(self, host, port=None, secure=None, window_manager=None, enable_pus
8885
# Setup proxy details if applicable.
8986
if proxy_host:
9087
if proxy_port is None:
91-
try:
92-
self.proxy_host, self.proxy_port = proxy_host.split(':')
93-
except ValueError:
94-
self.proxy_host, self.proxy_port = proxy_host, 8080
95-
else:
96-
self.proxy_port = int(self.proxy_port)
88+
self.proxy_host, self.proxy_port = to_host_port_tuple(proxy_host, default_port=8080)
9789
else:
9890
self.proxy_host, self.proxy_port = proxy_host, proxy_port
9991
else:

hyper/packages/rfc3986/LICENSE

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Copyright 2014 Ian Cordasco, Rackspace
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.

hyper/packages/rfc3986/__init__.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright (c) 2014 Rackspace
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
# implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
"""
17+
rfc3986
18+
=======
19+
20+
An implementation of semantics and validations described in RFC 3986. See
21+
http://rfc3986.rtfd.org/ for documentation.
22+
23+
:copyright: (c) 2014 Rackspace
24+
:license: Apache v2.0, see LICENSE for details
25+
"""
26+
27+
__title__ = 'rfc3986'
28+
__author__ = 'Ian Cordasco'
29+
__author_email__ = '[email protected]'
30+
__license__ = 'Apache v2.0'
31+
__copyright__ = 'Copyright 2014 Rackspace'
32+
__version__ = '0.3.0'
33+
34+
from .api import (URIReference, uri_reference, is_valid_uri, normalize_uri,
35+
urlparse)
36+
from .parseresult import ParseResult
37+
38+
__all__ = (
39+
'ParseResult',
40+
'URIReference',
41+
'is_valid_uri',
42+
'normalize_uri',
43+
'uri_reference',
44+
'urlparse',
45+
)

hyper/packages/rfc3986/api.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright (c) 2014 Rackspace
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
# implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
"""
16+
rfc3986.api
17+
~~~~~~~~~~~
18+
19+
This defines the simple API to rfc3986. This module defines 3 functions and
20+
provides access to the class ``URIReference``.
21+
"""
22+
23+
from .uri import URIReference
24+
from .parseresult import ParseResult
25+
26+
27+
def uri_reference(uri, encoding='utf-8'):
28+
"""Parse a URI string into a URIReference.
29+
30+
This is a convenience function. You could achieve the same end by using
31+
``URIReference.from_string(uri)``.
32+
33+
:param str uri: The URI which needs to be parsed into a reference.
34+
:param str encoding: The encoding of the string provided
35+
:returns: A parsed URI
36+
:rtype: :class:`URIReference`
37+
"""
38+
return URIReference.from_string(uri, encoding)
39+
40+
41+
def is_valid_uri(uri, encoding='utf-8', **kwargs):
42+
"""Determine if the URI given is valid.
43+
44+
This is a convenience function. You could use either
45+
``uri_reference(uri).is_valid()`` or
46+
``URIReference.from_string(uri).is_valid()`` to achieve the same result.
47+
48+
:param str uri: The URI to be validated.
49+
:param str encoding: The encoding of the string provided
50+
:param bool require_scheme: Set to ``True`` if you wish to require the
51+
presence of the scheme component.
52+
:param bool require_authority: Set to ``True`` if you wish to require the
53+
presence of the authority component.
54+
:param bool require_path: Set to ``True`` if you wish to require the
55+
presence of the path component.
56+
:param bool require_query: Set to ``True`` if you wish to require the
57+
presence of the query component.
58+
:param bool require_fragment: Set to ``True`` if you wish to require the
59+
presence of the fragment component.
60+
:returns: ``True`` if the URI is valid, ``False`` otherwise.
61+
:rtype: bool
62+
"""
63+
return URIReference.from_string(uri, encoding).is_valid(**kwargs)
64+
65+
66+
def normalize_uri(uri, encoding='utf-8'):
67+
"""Normalize the given URI.
68+
69+
This is a convenience function. You could use either
70+
``uri_reference(uri).normalize().unsplit()`` or
71+
``URIReference.from_string(uri).normalize().unsplit()`` instead.
72+
73+
:param str uri: The URI to be normalized.
74+
:param str encoding: The encoding of the string provided
75+
:returns: The normalized URI.
76+
:rtype: str
77+
"""
78+
normalized_reference = URIReference.from_string(uri, encoding).normalize()
79+
return normalized_reference.unsplit()
80+
81+
82+
def urlparse(uri, encoding='utf-8'):
83+
"""Parse a given URI and return a ParseResult.
84+
85+
This is a partial replacement of the standard library's urlparse function.
86+
87+
:param str uri: The URI to be parsed.
88+
:param str encoding: The encoding of the string provided.
89+
:returns: A parsed URI
90+
:rtype: :class:`~rfc3986.parseresult.ParseResult`
91+
"""
92+
return ParseResult.from_string(uri, encoding, strict=False)

hyper/packages/rfc3986/compat.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright (c) 2014 Rackspace
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
# implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
import sys
16+
17+
18+
if sys.version_info >= (3, 0):
19+
unicode = str # Python 3.x
20+
21+
22+
def to_str(b, encoding):
23+
if hasattr(b, 'decode') and not isinstance(b, unicode):
24+
b = b.decode('utf-8')
25+
return b
26+
27+
28+
def to_bytes(s, encoding):
29+
if hasattr(s, 'encode') and not isinstance(s, bytes):
30+
s = s.encode('utf-8')
31+
return s

0 commit comments

Comments
 (0)