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

Commit

Permalink
Merge pull request #172 from fredthomsen/validate_ipv6_support
Browse files Browse the repository at this point in the history
Validate ipv6 support
  • Loading branch information
Lukasa committed Nov 18, 2015
2 parents eb57b92 + e8dd399 commit e7ce870
Show file tree
Hide file tree
Showing 18 changed files with 1,285 additions and 25 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS.rst
Expand Up @@ -37,3 +37,4 @@ In chronological order:

- Added support for upgrade of plaintext HTTP/1.1 to plaintext HTTP/2.
- Added proxy support.
- Improved IPv6 support.
16 changes: 16 additions & 0 deletions NOTICES
Expand Up @@ -20,3 +20,19 @@ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

rfc3986:

Copyright 2014 Ian Cordasco, Rackspace

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
4 changes: 2 additions & 2 deletions hyper/cli.py
Expand Up @@ -17,6 +17,7 @@
from hyper import HTTPConnection, HTTP20Connection
from hyper import __version__
from hyper.compat import is_py2, urlencode, urlsplit, write_to_stdout
from hyper.common.util import to_host_port_tuple


log = logging.getLogger('hyper')
Expand Down Expand Up @@ -113,8 +114,7 @@ def make_troubleshooting_argument(parser):
def set_url_info(args):
def split_host_and_port(hostname):
if ':' in hostname:
host, port = hostname.split(':')
return host, int(port)
return to_host_port_tuple(hostname, default_port=443)
return hostname, None

class UrlInfo(object):
Expand Down
23 changes: 23 additions & 0 deletions hyper/common/util.py
Expand Up @@ -6,6 +6,8 @@
General utility functions for use with hyper.
"""
from hyper.compat import unicode, bytes, imap
from ..packages.rfc3986.uri import URIReference
import re

def to_bytestring(element):
"""
Expand All @@ -25,3 +27,24 @@ def to_bytestring_tuple(*x):
tuple. Uses ``to_bytestring``.
"""
return tuple(imap(to_bytestring, x))

def to_host_port_tuple(host_port_str, default_port=80):
"""
Converts the given string containing a host and possibly a port
to a tuple.
"""
uri = URIReference(
scheme=None,
authority=host_port_str,
path=None,
query=None,
fragment=None
)

host = uri.host.strip('[]')
if not uri.port:
port = default_port
else:
port = int(uri.port)

return (host, port)
15 changes: 3 additions & 12 deletions hyper/http11/connection.py
Expand Up @@ -15,7 +15,7 @@
from ..common.bufsocket import BufferedSocket
from ..common.exceptions import TLSUpgrade, HTTPUpgrade
from ..common.headers import HTTPHeaderMap
from ..common.util import to_bytestring
from ..common.util import to_bytestring, to_host_port_tuple
from ..compat import bytes

from ..packages.hyperframe.frame import SettingsFrame
Expand Down Expand Up @@ -56,11 +56,7 @@ class HTTP11Connection(object):
def __init__(self, host, port=None, secure=None, ssl_context=None,
proxy_host=None, proxy_port=None, **kwargs):
if port is None:
try:
self.host, self.port = host.split(':')
self.port = int(self.port)
except ValueError:
self.host, self.port = host, 80
self.host, self.port = to_host_port_tuple(host, default_port=80)
else:
self.host, self.port = host, port

Expand All @@ -83,12 +79,7 @@ def __init__(self, host, port=None, secure=None, ssl_context=None,
# Setup proxy details if applicable.
if proxy_host:
if proxy_port is None:
try:
self.proxy_host, self.proxy_port = proxy_host.split(':')
except ValueError:
self.proxy_host, self.proxy_port = proxy_host, 8080
else:
self.proxy_port = int(self.proxy_port)
self.proxy_host, self.proxy_port = to_host_port_tuple(proxy_host, default_port=8080)
else:
self.proxy_host, self.proxy_port = proxy_host, proxy_port
else:
Expand Down
14 changes: 3 additions & 11 deletions hyper/http20/connection.py
Expand Up @@ -9,6 +9,7 @@
from ..common.exceptions import ConnectionResetError
from ..common.bufsocket import BufferedSocket
from ..common.headers import HTTPHeaderMap
from ..common.util import to_host_port_tuple
from ..packages.hyperframe.frame import (
FRAMES, DataFrame, HeadersFrame, PushPromiseFrame, RstStreamFrame,
SettingsFrame, Frame, WindowUpdateFrame, GoAwayFrame, PingFrame,
Expand Down Expand Up @@ -67,11 +68,7 @@ def __init__(self, host, port=None, secure=None, window_manager=None, enable_pus
Creates an HTTP/2 connection to a specific server.
"""
if port is None:
try:
self.host, self.port = host.split(':')
self.port = int(self.port)
except ValueError:
self.host, self.port = host, 443
self.host, self.port = to_host_port_tuple(host, default_port=443)
else:
self.host, self.port = host, port

Expand All @@ -88,12 +85,7 @@ def __init__(self, host, port=None, secure=None, window_manager=None, enable_pus
# Setup proxy details if applicable.
if proxy_host:
if proxy_port is None:
try:
self.proxy_host, self.proxy_port = proxy_host.split(':')
except ValueError:
self.proxy_host, self.proxy_port = proxy_host, 8080
else:
self.proxy_port = int(self.proxy_port)
self.proxy_host, self.proxy_port = to_host_port_tuple(proxy_host, default_port=8080)
else:
self.proxy_host, self.proxy_port = proxy_host, proxy_port
else:
Expand Down
13 changes: 13 additions & 0 deletions hyper/packages/rfc3986/LICENSE
@@ -0,0 +1,13 @@
Copyright 2014 Ian Cordasco, Rackspace

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
45 changes: 45 additions & 0 deletions hyper/packages/rfc3986/__init__.py
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2014 Rackspace
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
rfc3986
=======
An implementation of semantics and validations described in RFC 3986. See
http://rfc3986.rtfd.org/ for documentation.
:copyright: (c) 2014 Rackspace
:license: Apache v2.0, see LICENSE for details
"""

__title__ = 'rfc3986'
__author__ = 'Ian Cordasco'
__author_email__ = 'ian.cordasco@rackspace.com'
__license__ = 'Apache v2.0'
__copyright__ = 'Copyright 2014 Rackspace'
__version__ = '0.3.0'

from .api import (URIReference, uri_reference, is_valid_uri, normalize_uri,
urlparse)
from .parseresult import ParseResult

__all__ = (
'ParseResult',
'URIReference',
'is_valid_uri',
'normalize_uri',
'uri_reference',
'urlparse',
)
92 changes: 92 additions & 0 deletions hyper/packages/rfc3986/api.py
@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2014 Rackspace
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
rfc3986.api
~~~~~~~~~~~
This defines the simple API to rfc3986. This module defines 3 functions and
provides access to the class ``URIReference``.
"""

from .uri import URIReference
from .parseresult import ParseResult


def uri_reference(uri, encoding='utf-8'):
"""Parse a URI string into a URIReference.
This is a convenience function. You could achieve the same end by using
``URIReference.from_string(uri)``.
:param str uri: The URI which needs to be parsed into a reference.
:param str encoding: The encoding of the string provided
:returns: A parsed URI
:rtype: :class:`URIReference`
"""
return URIReference.from_string(uri, encoding)


def is_valid_uri(uri, encoding='utf-8', **kwargs):
"""Determine if the URI given is valid.
This is a convenience function. You could use either
``uri_reference(uri).is_valid()`` or
``URIReference.from_string(uri).is_valid()`` to achieve the same result.
:param str uri: The URI to be validated.
:param str encoding: The encoding of the string provided
:param bool require_scheme: Set to ``True`` if you wish to require the
presence of the scheme component.
:param bool require_authority: Set to ``True`` if you wish to require the
presence of the authority component.
:param bool require_path: Set to ``True`` if you wish to require the
presence of the path component.
:param bool require_query: Set to ``True`` if you wish to require the
presence of the query component.
:param bool require_fragment: Set to ``True`` if you wish to require the
presence of the fragment component.
:returns: ``True`` if the URI is valid, ``False`` otherwise.
:rtype: bool
"""
return URIReference.from_string(uri, encoding).is_valid(**kwargs)


def normalize_uri(uri, encoding='utf-8'):
"""Normalize the given URI.
This is a convenience function. You could use either
``uri_reference(uri).normalize().unsplit()`` or
``URIReference.from_string(uri).normalize().unsplit()`` instead.
:param str uri: The URI to be normalized.
:param str encoding: The encoding of the string provided
:returns: The normalized URI.
:rtype: str
"""
normalized_reference = URIReference.from_string(uri, encoding).normalize()
return normalized_reference.unsplit()


def urlparse(uri, encoding='utf-8'):
"""Parse a given URI and return a ParseResult.
This is a partial replacement of the standard library's urlparse function.
:param str uri: The URI to be parsed.
:param str encoding: The encoding of the string provided.
:returns: A parsed URI
:rtype: :class:`~rfc3986.parseresult.ParseResult`
"""
return ParseResult.from_string(uri, encoding, strict=False)
31 changes: 31 additions & 0 deletions hyper/packages/rfc3986/compat.py
@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2014 Rackspace
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys


if sys.version_info >= (3, 0):
unicode = str # Python 3.x


def to_str(b, encoding):
if hasattr(b, 'decode') and not isinstance(b, unicode):
b = b.decode('utf-8')
return b


def to_bytes(s, encoding):
if hasattr(s, 'encode') and not isinstance(s, bytes):
s = s.encode('utf-8')
return s
21 changes: 21 additions & 0 deletions hyper/packages/rfc3986/exceptions.py
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
class RFC3986Exception(Exception):
pass


class InvalidAuthority(RFC3986Exception):
def __init__(self, authority):
super(InvalidAuthority, self).__init__(
"The authority ({0}) is not valid.".format(authority))


class InvalidPort(RFC3986Exception):
def __init__(self, port):
super(InvalidPort, self).__init__(
'The port ("{0}") is not valid.'.format(port))


class ResolutionError(RFC3986Exception):
def __init__(self, uri):
super(ResolutionError, self).__init__(
"{0} is not an absolute URI.".format(uri.unsplit()))

0 comments on commit e7ce870

Please sign in to comment.