make host url parsing more resilient
Reject invalid combinations of url scheme and connection_class
This commit is contained in:
@@ -29,7 +29,7 @@ def _normalize_hosts(hosts):
|
|||||||
|
|
||||||
out = []
|
out = []
|
||||||
# normalize hosts to dicts
|
# normalize hosts to dicts
|
||||||
for i, host in enumerate(hosts):
|
for host in hosts:
|
||||||
if isinstance(host, string_types):
|
if isinstance(host, string_types):
|
||||||
if '://' not in host:
|
if '://' not in host:
|
||||||
host = "//%s" % host
|
host = "//%s" % host
|
||||||
@@ -43,11 +43,10 @@ def _normalize_hosts(hosts):
|
|||||||
if parsed_url.scheme == "https":
|
if parsed_url.scheme == "https":
|
||||||
h['port'] = parsed_url.port or 443
|
h['port'] = parsed_url.port or 443
|
||||||
h['use_ssl'] = True
|
h['use_ssl'] = True
|
||||||
elif parsed_url.scheme == "http":
|
h['scheme'] = 'http'
|
||||||
logger.warning(
|
|
||||||
"List of nodes should not include schema information (http://): %r.",
|
elif parsed_url.scheme:
|
||||||
host
|
h['scheme'] = parsed_url.scheme
|
||||||
)
|
|
||||||
|
|
||||||
if parsed_url.username or parsed_url.password:
|
if parsed_url.username or parsed_url.password:
|
||||||
h['http_auth'] = '%s:%s' % (parsed_url.username, parsed_url.password)
|
h['http_auth'] = '%s:%s' % (parsed_url.username, parsed_url.password)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from .connection import Urllib3HttpConnection
|
|||||||
from .connection_pool import ConnectionPool
|
from .connection_pool import ConnectionPool
|
||||||
from .serializer import JSONSerializer, Deserializer, DEFAULT_SERIALIZERS
|
from .serializer import JSONSerializer, Deserializer, DEFAULT_SERIALIZERS
|
||||||
from .exceptions import ConnectionError, TransportError, SerializationError, \
|
from .exceptions import ConnectionError, TransportError, SerializationError, \
|
||||||
ConnectionTimeout
|
ConnectionTimeout, ImproperlyConfigured
|
||||||
|
|
||||||
# get ip/port from "inet[wind/127.0.0.1:9200]"
|
# get ip/port from "inet[wind/127.0.0.1:9200]"
|
||||||
ADDRESS_RE = re.compile(r'/(?P<host>[\.:0-9a-f]*):(?P<port>[0-9]+)\]?$')
|
ADDRESS_RE = re.compile(r'/(?P<host>[\.:0-9a-f]*):(?P<port>[0-9]+)\]?$')
|
||||||
@@ -153,6 +153,12 @@ class Transport(object):
|
|||||||
# previously unseen params, create new connection
|
# previously unseen params, create new connection
|
||||||
kwargs = self.kwargs.copy()
|
kwargs = self.kwargs.copy()
|
||||||
kwargs.update(host)
|
kwargs.update(host)
|
||||||
|
|
||||||
|
if 'scheme' in host and host['scheme'] != self.connection_class.transport_schema:
|
||||||
|
raise ImproperlyConfigured(
|
||||||
|
'Scheme specified in connection (%s) is not the same as the connection class (%s) specifies (%s).' % (
|
||||||
|
host['scheme'], self.connection_class.__name__, self.connection_class.transport_schema
|
||||||
|
))
|
||||||
return self.connection_class(**kwargs)
|
return self.connection_class(**kwargs)
|
||||||
connections = map(_create_connection, hosts)
|
connections = map(_create_connection, hosts)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from mock import patch
|
|
||||||
|
|
||||||
from elasticsearch.client import _normalize_hosts, Elasticsearch
|
from elasticsearch.client import _normalize_hosts, Elasticsearch
|
||||||
|
|
||||||
from ..test_cases import TestCase, ElasticsearchTestCase
|
from ..test_cases import TestCase, ElasticsearchTestCase
|
||||||
@@ -21,23 +19,16 @@ class TestNormalizeHosts(TestCase):
|
|||||||
|
|
||||||
def test_strings_are_parsed_for_scheme(self):
|
def test_strings_are_parsed_for_scheme(self):
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
[{"host": "elasticsearch.org", "port": 42, "use_ssl": True},
|
[
|
||||||
{"host": "elasticsearch.com", "http_auth": "user:secret", "use_ssl": True, "port": 443}],
|
{"host": "elasticsearch.org", "port": 42, "use_ssl": True, 'scheme': 'http'},
|
||||||
|
{"host": "elasticsearch.com", "http_auth": "user:secret", "use_ssl": True, "port": 443, 'scheme': 'http'}
|
||||||
|
],
|
||||||
_normalize_hosts(["https://elasticsearch.org:42", "https://user:[email protected]"])
|
_normalize_hosts(["https://elasticsearch.org:42", "https://user:[email protected]"])
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_dicts_are_left_unchanged(self):
|
def test_dicts_are_left_unchanged(self):
|
||||||
self.assertEquals([{"host": "local", "extra": 123}], _normalize_hosts([{"host": "local", "extra": 123}]))
|
self.assertEquals([{"host": "local", "extra": 123}], _normalize_hosts([{"host": "local", "extra": 123}]))
|
||||||
|
|
||||||
@patch('elasticsearch.client.logger')
|
|
||||||
def test_schema_is_stripped_out(self, logger):
|
|
||||||
self.assertEquals(
|
|
||||||
[{"host": "elasticsearch.org", "port": 9200}],
|
|
||||||
_normalize_hosts(["http://elasticsearch.org:9200/"])
|
|
||||||
)
|
|
||||||
# schema triggers a warning
|
|
||||||
self.assertEquals(1, logger.warning.call_count)
|
|
||||||
|
|
||||||
def test_single_string_is_wrapped_in_list(self):
|
def test_single_string_is_wrapped_in_list(self):
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
[{"host": "elasticsearch.org"}],
|
[{"host": "elasticsearch.org"}],
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ from __future__ import unicode_literals
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from elasticsearch.transport import Transport, get_host_info
|
from elasticsearch.transport import Transport, get_host_info
|
||||||
from elasticsearch.connection import Connection
|
from elasticsearch.connection import Connection, ThriftConnection
|
||||||
from elasticsearch.exceptions import ConnectionError
|
from elasticsearch.exceptions import ConnectionError, ImproperlyConfigured
|
||||||
|
|
||||||
from .test_cases import TestCase
|
from .test_cases import TestCase
|
||||||
|
|
||||||
@@ -52,6 +52,10 @@ class TestHostsInfoCallback(TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class TestTransport(TestCase):
|
class TestTransport(TestCase):
|
||||||
|
def test_host_with_scheme_different_from_connection_fails(self):
|
||||||
|
self.assertRaises(ImproperlyConfigured, Transport, [{'host': 'localhost', 'scheme': 'thrift'}])
|
||||||
|
self.assertRaises(ImproperlyConfigured, Transport, [{'host': 'localhost', 'scheme': 'http'}], connection_class=ThriftConnection)
|
||||||
|
|
||||||
def test_request_timeout_extracted_from_params_and_passed(self):
|
def test_request_timeout_extracted_from_params_and_passed(self):
|
||||||
t = Transport([{}], connection_class=DummyConnection)
|
t = Transport([{}], connection_class=DummyConnection)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user