Repository: Azure/WALinuxAgent
Pull request #1416 (2018-12-06 17:52:39)

Fix utf-8 encoding for telemetry payload
<!-- DO NOT DELETE THIS TEMPLATE -->

## Description

Added utf-8 encoding when sending telemetry payload, compatible with Python 2 and 3. Added unit test.

Issue #1344  <!-- if any -->
<!--
Please add an informative description that covers that changes made by the pull request. 
This checklist is used to make sure that common issues in a pull request are addressed.
This will expedite the process of getting your pull request merged and avoid extra work on your part to fix issues discovered during the review process.
-->

---

### PR information
- [x] The title of the PR is clear and informative.
- [x] There are a small number of commits, each of which has an informative message. This means that previously merged commits do not appear in the history of the PR. For information on cleaning up the commits in your pull request, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md).
- [x] Except for special cases involving multiple contributors, the PR is started from a fork of the main repository, not a branch.
- [x] If applicable, the PR references the bug/issue that it fixes in the description.
- [x] New Unit tests were added for the changes made and Travis.CI is passing.

### Quality of Code and Contribution Guidelines
- [x] I have read the [contribution guidelines](https://github.com/Azure/WALinuxAgent/blob/master/.github/CONTRIBUTING.md).


Patch:
diff --git a/azurelinuxagent/common/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py
index 18ba8174..9eac6215 100644
--- a/azurelinuxagent/common/protocol/wire.py
+++ b/azurelinuxagent/common/protocol/wire.py
@@ -1114,6 +1114,8 @@ class WireClient(object):
                        '<Provider id="{0}">{1}'
                        '</Provider>'
                        '</TelemetryData>')
+        if event_str:
+            event_str = event_str.encode("utf-8")
         data = data_format.format(provider_id, event_str)
         try:
             header = self.get_header_for_xml_content()
diff --git a/azurelinuxagent/common/utils/restutil.py b/azurelinuxagent/common/utils/restutil.py
index 97109a87..d8f93d2e 100644
--- a/azurelinuxagent/common/utils/restutil.py
+++ b/azurelinuxagent/common/utils/restutil.py
@@ -247,24 +247,26 @@ def get_no_proxy():
 def bypass_proxy(host):
     no_proxy = get_no_proxy()
 
-    if is_ipv4_address(host):
-        for proxy_ip in no_proxy:
-            if is_valid_cidr(proxy_ip):
-                if address_in_network(host, proxy_ip):
+    if no_proxy:
+        if is_ipv4_address(host):
+            for proxy_ip in no_proxy:
+                if is_valid_cidr(proxy_ip):
+                    if address_in_network(host, proxy_ip):
+                        return True
+                elif host == proxy_ip:
+                    # If no_proxy ip was defined in plain IP notation instead of cidr notation &
+                    # matches the IP of the index
+                    return True
+        else:
+            for proxy_domain in no_proxy:
+                if host.lower().endswith(proxy_domain.lower()):
+                    # The URL does match something in no_proxy, so we don't want
+                    # to apply the proxies on this URL.
                     return True
-            elif host == proxy_ip:
-                # If no_proxy ip was defined in plain IP notation instead of cidr notation &
-                # matches the IP of the index
-                return True
-    else:
-        for proxy_domain in no_proxy:
-            if host.lower().endswith(proxy_domain.lower()):
-                # The URL does match something in no_proxy, so we don't want
-                # to apply the proxies on this URL.
-                return True
 
     return False
 
+
 def _get_http_proxy(secure=False):
     # Prefer the configuration settings over environment variables
     host = conf.get_httpproxy_host()


Test patch:
diff --git a/tests/protocol/test_wire.py b/tests/protocol/test_wire.py
index 45b1dca0..27d4dbbb 100644
--- a/tests/protocol/test_wire.py
+++ b/tests/protocol/test_wire.py
@@ -1,3 +1,4 @@
+# -*- encoding: utf-8 -*-
 # Copyright 2018 Microsoft Corporation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -442,6 +443,22 @@ class TestWireProtocol(AgentTestCase):
         }
         self.assertEqual(json.dumps(v1_vm_status), actual.to_json())
 
+    @patch("azurelinuxagent.common.utils.restutil.http_request")
+    def test_send_event(self, mock_http_request, *args):
+        mock_http_request.return_value = MockResponse("", 200)
+
+        event_str = u'ćevapčići検索システムκόσμε片仮名'
+        client = WireProtocol(wireserver_url).client
+        client.send_event("foo", event_str)
+
+        first_call = mock_http_request.call_args_list[0]
+        args, kwargs = first_call
+        method, url, body_received = args
+        headers = kwargs['headers']
+
+        self.assertTrue("utf-8" in headers['Content-Type'])
+        self.assertIn(str(event_str.encode("utf-8")), body_received)
+
 
 class MockResponse:
     def __init__(self, body, status_code):
diff --git a/tests/utils/test_rest_util.py b/tests/utils/test_rest_util.py
index 2bcda05d..8216e5e5 100644
--- a/tests/utils/test_rest_util.py
+++ b/tests/utils/test_rest_util.py
@@ -454,6 +454,54 @@ class TestHttpOperations(AgentTestCase):
             host = "10.0.1.1"
             self.assertEquals(should_use_proxy, use_proxy and not restutil.bypass_proxy(host))
 
+        # When No_proxy is empty
+        with patch.dict(os.environ, {
+            'no_proxy': ""
+        }):
+            host = "10.0.0.1"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+            host = "foo.com"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+            host = "www.google.com"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+            host = "168.63.129.16"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+            host = "www.bar.com"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+            host = "10.0.0.1"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+            host = "10.0.1.1"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+        # When os.environ is empty - No global variables defined.
+        with patch.dict(os.environ, {}):
+            host = "10.0.0.1"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+            host = "foo.com"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+            host = "www.google.com"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+            host = "168.63.129.16"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+            host = "www.bar.com"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+            host = "10.0.0.1"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
+            host = "10.0.1.1"
+            self.assertTrue(use_proxy and not restutil.bypass_proxy(host))
+
     @patch("azurelinuxagent.common.future.httpclient.HTTPSConnection")
     @patch("azurelinuxagent.common.future.httpclient.HTTPConnection")
     def test_http_request_proxy_secure(self, HTTPConnection, HTTPSConnection):