From c51ef2e3eaba87ef254e6d9dbf39921edca1d3be Mon Sep 17 00:00:00 2001 From: Michael Graeb Date: Thu, 19 Sep 2019 15:24:32 -0700 Subject: [PATCH] tests for TlsConnectionOptions, alpn_list is now actually a list (#69) --- awscrt/io.py | 14 ++++++++++++-- codebuild/common-linux.sh | 9 ++++++++- codebuild/common-macos.sh | 7 ++++++- elasticurl.py | 13 ++++++------- mqtt_test.py | 2 +- setup.cfg | 2 ++ test/test_io.py | 21 ++++++++++++++++++++- 7 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 setup.cfg diff --git a/awscrt/io.py b/awscrt/io.py index f27d8795d..f18595e6f 100644 --- a/awscrt/io.py +++ b/awscrt/io.py @@ -226,6 +226,16 @@ def create_server_pkcs12(pkcs12_filepath, pkcs12_password): opt.verify_peer = False return opt +def _alpn_list_to_str(alpn_list): + """ + Transform ['h2', 'http/1.1'] -> "h2;http/1.1" + None is returned if list is None or empty + """ + if alpn_list: + assert not isinstance_str(alpn_list) + return ';'.join(alpn_list) + return None + class ClientTlsContext(NativeResource): __slots__ = () @@ -238,7 +248,7 @@ def __init__(self, options): options.min_tls_ver.value, options.ca_dirpath, options.ca_buffer, - options.alpn_list, + _alpn_list_to_str(options.alpn_list), options.certificate_buffer, options.private_key_buffer, options.pkcs12_filepath, @@ -261,7 +271,7 @@ def __init__(self, tls_ctx): self._binding = _awscrt.tls_connections_options_new_from_ctx(tls_ctx) def set_alpn_list(self, alpn_list): - _awscrt.tls_connection_options_set_alpn_list(self, alpn_list) + _awscrt.tls_connection_options_set_alpn_list(self, _alpn_list_to_str(alpn_list)) def set_server_name(self, server_name): _awscrt.tls_connection_options_set_server_name(self, server_name) diff --git a/codebuild/common-linux.sh b/codebuild/common-linux.sh index 0625aa5b1..0cbf41d48 100755 --- a/codebuild/common-linux.sh +++ b/codebuild/common-linux.sh @@ -21,7 +21,14 @@ cert=$(aws secretsmanager get-secret-value --secret-id "unit-test/certificate" - key=$(aws secretsmanager get-secret-value --secret-id "unit-test/privatekey" --query "SecretString" | cut -f2 -d":" | cut -f2 -d\") && echo -e "$key" > /tmp/privatekey.pem ENDPOINT=$(aws secretsmanager get-secret-value --secret-id "unit-test/endpoint" --query "SecretString" | cut -f2 -d":" | sed -e 's/[\\\"\}]//g') +echo --- unittest --- python3 -m unittest discover -python3 elasticurl.py -v ERROR -P -H "content-type: application/json" -i -d "{'test':'testval'}" http://httpbin.org/post + +echo --- elasticurl GET --- python3 elasticurl.py -v ERROR -i https://example.com + +echo --- elasticurl PUT --- +python3 elasticurl.py -v ERROR -P -H "content-type: application/json" -i -d "{'test':'testval'}" http://httpbin.org/post + +echo --- mqtt --- python3 mqtt_test.py --endpoint $ENDPOINT --port 8883 --cert /tmp/certificate.pem --key /tmp/privatekey.pem --root-ca /tmp/AmazonRootCA1.pem diff --git a/codebuild/common-macos.sh b/codebuild/common-macos.sh index cd52c4b82..7f14b41bc 100755 --- a/codebuild/common-macos.sh +++ b/codebuild/common-macos.sh @@ -36,6 +36,11 @@ export AWS_C_INSTALL=`pwd`/build/deps/install # build python3 extension python3 setup.py build install +echo --- unittest --- python3 -m unittest discover -python3 elasticurl.py -v ERROR -P -H "content-type: application/json" -i -d "{'test':'testval'}" http://httpbin.org/post + +echo --- elasticurl GET --- python3 elasticurl.py -v ERROR -i https://example.com + +echo --- elasticurl PUT --- +python3 elasticurl.py -v ERROR -P -H "content-type: application/json" -i -d "{'test':'testval'}" http://httpbin.org/post diff --git a/elasticurl.py b/elasticurl.py index 01477e808..8de4d8b70 100644 --- a/elasticurl.py +++ b/elasticurl.py @@ -33,7 +33,7 @@ def print_header_list(headers): parser.add_argument('--cert', required=False, help='FILE: path to a PEM encoded certificate to use with mTLS') parser.add_argument('--key', required=False, help='FILE: Path to a PEM encoded private key that matches cert.') parser.add_argument('--connect_timeout', required=False, type=int, help='INT: time in milliseconds to wait for a connection.', default=3000) -parser.add_argument('-H', '--header', required=False, help='LINE: line to send as a header in format [header-key]: [header-value]\n', nargs='*', action='append') +parser.add_argument('-H', '--header', required=False, help='STRING: line to send as a header in format "name:value". May be specified multiple times.', action='append') parser.add_argument('-d', '--data', required=False, help='STRING: Data to POST or PUT.') parser.add_argument('--data_file', required=False, help='FILE: File to read from file and POST or PUT') parser.add_argument('-M', '--method', required=False, help='STRING: Http Method verb to use for the request', default='GET') @@ -44,7 +44,7 @@ def print_header_list(headers): parser.add_argument('-k', '--insecure', required=False, help='Turns off x.509 validation', action='store_true', default=False) parser.add_argument('-o', '--output', required=False, help='FILE: dumps content-body to FILE instead of stdout.') parser.add_argument('-t', '--trace', required=False, help='FILE: dumps logs to FILE instead of stderr.') -parser.add_argument('-p', '--alpn_list', required=False, help='STRING: List of protocols for ALPN, semi-colon delimited') +parser.add_argument('-p', '--alpn', required=False, help='STRING: protocol for ALPN. May be specified multiple times.', action='append') parser.add_argument('-v', '--verbose', required=False, help='ERROR|INFO|DEBUG|TRACE: log level to configure. Default is none.') args = parser.parse_args() @@ -119,8 +119,8 @@ def print_header_list(headers): tls_connection_options = tls_ctx.new_connection_options() tls_connection_options.set_server_name(url.hostname) - if args.alpn_list: - tls_connection_options.set_alpn_list(args.alpn_list) + if args.alpn: + tls_connection_options.set_alpn_list(args.alpn) # invoked up on the connection closing def on_connection_shutdown(err_code): @@ -178,9 +178,8 @@ def on_incoming_body(http_stream, body_data): if args.header: for i in args.header: - name_value_tuple = i[0].split(':') - request.headers.add(name_value_tuple[0].strip(), name_value_tuple[1].strip()) - + name, value = i.split(':') + request.headers.add(name.strip(), value.strip()) # invoked as soon as the response headers are received def response_received_cb(http_stream, status_code, headers): diff --git a/mqtt_test.py b/mqtt_test.py index 713ca65e9..963e8fd3e 100644 --- a/mqtt_test.py +++ b/mqtt_test.py @@ -69,7 +69,7 @@ def on_receive_message(topic, message): elif io.is_alpn_available(): port = 443 if tls_options: - tls_options.alpn_list='x-amzn-mqtt-ca' + tls_options.alpn_list = ['x-amzn-mqtt-ca'] else: port = 8883 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 000000000..68859ad03 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[pep8] +max-line-length = 120 diff --git a/test/test_io.py b/test/test_io.py index 7c8b1ddcb..90effb6db 100644 --- a/test/test_io.py +++ b/test/test_io.py @@ -12,7 +12,7 @@ # permissions and limitations under the License. from __future__ import absolute_import -from awscrt.io import ClientBootstrap, ClientTlsContext, DefaultHostResolver, EventLoopGroup, TlsContextOptions +from awscrt.io import ClientBootstrap, ClientTlsContext, DefaultHostResolver, EventLoopGroup, TlsConnectionOptions, TlsContextOptions from test import NativeResourceTest import unittest @@ -68,5 +68,24 @@ def test_override_default_trust_store_file(self): ctx = ClientTlsContext(opt) +class TlsConnectionOptionsTest(NativeResourceTest): + def test_init(self): + opt = TlsContextOptions() + ctx = ClientTlsContext(opt) + conn_opt = TlsConnectionOptions(ctx) + + def test_alpn_list(self): + opt = TlsContextOptions() + ctx = ClientTlsContext(opt) + conn_opt = TlsConnectionOptions(ctx) + conn_opt.set_alpn_list(['h2', 'http/1.1']) + + def test_server_name(self): + opt = TlsContextOptions() + ctx = ClientTlsContext(opt) + conn_opt = TlsConnectionOptions(ctx) + conn_opt.set_server_name('localhost') + + if __name__ == '__main__': unittest.main()