Skip to content

Commit

Permalink
Modify HTTP logs in clients for safety and clarity
Browse files Browse the repository at this point in the history
Refs grnet#32

Implement method escape_ctrl_chars
Escape control characters in HTTP data logs
Remove misleading separators from HTTP logs
  • Loading branch information
saxtouri committed Sep 26, 2014
1 parent 14ef92c commit 6b13c26
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 11 deletions.
19 changes: 8 additions & 11 deletions kamaki/clients/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@

from kamaki.clients.utils import https

from kamaki.clients import utils


TIMEOUT = 60.0 # seconds
HTTP_METHODS = ['GET', 'POST', 'PUT', 'HEAD', 'DELETE', 'COPY', 'MOVE']
Expand Down Expand Up @@ -148,7 +150,6 @@ def __init__(

def dump_log(self):
plog = ('\t[%s]' % self) if self.LOG_PID else ''
sendlog.info('- - - - - - -')
sendlog.info('%s %s://%s%s%s' % (
self.method, self.scheme, self.netloc, self.path, plog))
for key, val in self.headers.items():
Expand All @@ -158,8 +159,8 @@ def dump_log(self):
if self.data:
sendlog.info('data size: %s%s' % (len(self.data), plog))
if self.LOG_DATA:
sendlog.info(self.data.replace(self._token, '...') if (
self._token) else self.data)
sendlog.info(utils.escape_ctrl_chars(self.data.replace(
self._token, '...') if self._token else self.data))
else:
sendlog.info('data size: 0%s' % plog)

Expand Down Expand Up @@ -274,8 +275,7 @@ def _get_response(self):
self._status_code, self._status = r.status, unquote(
r.reason)
recvlog.info(
'%d %s%s' % (
self.status_code, self.status, plog))
'%d %s%s' % (self.status_code, self.status, plog))
self._headers = dict()

r_headers = r.getheaders()
Expand All @@ -291,8 +291,7 @@ def _get_response(self):
data = '%s%s' % (self._content, plog)
if self._token:
data = data.replace(self._token, '...')
recvlog.info(data)
recvlog.info('- - - - - - -')
recvlog.info(utils.escape_ctrl_chars(data))
break
except Exception as err:
if isinstance(err, HTTPException):
Expand Down Expand Up @@ -382,11 +381,9 @@ def run(self):
try:
self._value = self.method(*(self.args), **(self.kwargs))
except Exception as e:
estatus = e.status if isinstance(e, ClientError) else ''
recvlog.debug('Thread %s got exception %s\n<%s %s' % (
self,
type(e),
e.status if isinstance(e, ClientError) else '',
e))
self, type(e), estatus, e))
self._exception = e


Expand Down
12 changes: 12 additions & 0 deletions kamaki/clients/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.

import unicodedata

def _matches(val1, val2, exactMath=True):
"""Case Insensitive match"""
Expand Down Expand Up @@ -105,3 +106,14 @@ def readall(openfile, size, retries=7):
continue
return buf
raise IOError('Failed to read %s bytes from file' % size)


def escape_ctrl_chars(s):
"""Escape control characters from unicode and string objects."""
if isinstance(s, unicode):
return "".join(ch.encode("unicode_escape") if (
unicodedata.category(ch)[0]) == "C" else ch for ch in s)
if isinstance(s, basestring):
return "".join(
[c if 31 < ord(c) < 127 else c.encode("string_escape") for c in s])
return s
19 changes: 19 additions & 0 deletions kamaki/clients/utils/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

from unittest import TestCase
from tempfile import TemporaryFile
from itertools import product

from kamaki.clients import utils

Expand Down Expand Up @@ -140,6 +141,24 @@ def test_readall(self):
self.assertEqual(utils.readall(f, 1), '')
self.assertRaises(IOError, utils.readall, f, 1, 0)

def test_escape_ctrl_chars(self):
gr_synnefo = u'\u03c3\u03cd\u03bd\u03bd\u03b5\u03c6\u03bf'
gr_kamaki = u'\u03ba\u03b1\u03bc\u03ac\u03ba\u03b9'

char_pairs = (
('\b', '\\x08'), ('\n', '\\n'), ('\a', '\\x07'), ('\f', '\\x0c'),
('\t', '\\t'), ('\v', '\\x0b'), ('\r', '\\r'), ('\072', ':'),
('\016', '\\x0e'), ('\\', '\\'), ('\\n', '\\n'), ("'", '\''),
('"', '"'),
)

for orig_char, esc_char in char_pairs:
for word1, word2 in product(
('synnefo', gr_kamaki), ('kamaki', gr_synnefo)):
orig_str = word1 + orig_char + word2
esc_str = word1 + esc_char + word2
self.assertEqual(utils.escape_ctrl_chars(orig_str), esc_str)

if __name__ == '__main__':
from sys import argv
from kamaki.clients.test import runTestCase
Expand Down

0 comments on commit 6b13c26

Please sign in to comment.