Repository: betamaxpy/betamax

Issue:
A blank string used for placeholder replacement can cause memory issue
**Version: betamax-0.8.0**

If you define a placeholder as described in the following, it can lead to memory issues, depending on how many blank strings you're trying to replace.

```python
username = ''
config.define_cassette_placeholder('<USERNAME>', username)
```

For example, if I have the original string `'WOW'` and perform the `.replace()` function, it will result in the following.
 ```python
>>> 'WOW'.replace('','<USERNAME>')
'<USERNAME>W<USERNAME>O<USERNAME>W<USERNAME>'
```

If you have multiple placeholders with a blank string, this compounds and can cause a memory issue. I experienced this issue in `src.betamax.cassette.interaction.py::Interaction::replace_in_uri`, but would think this is applicable to all functions that use `str.replace()` and it looks like it exists on the most current version of betamax too.

I can submit a PR to check for blank strings prior to calling `str.replace()`, but figure I'd bring it up in an issue first.

Discussion:

Patch:
diff --git a/src/betamax/cassette/interaction.py b/src/betamax/cassette/interaction.py
index f545bdb..799a8d5 100644
--- a/src/betamax/cassette/interaction.py
+++ b/src/betamax/cassette/interaction.py
@@ -69,6 +69,8 @@ class Interaction(object):
             self.replace(*placeholder.unpack(serializing))
 
     def replace_in_headers(self, text_to_replace, placeholder):
+        if text_to_replace == '':
+            return
         for obj in ('request', 'response'):
             headers = self.data[obj]['headers']
             for k, v in list(headers.items()):
@@ -79,6 +81,8 @@ class Interaction(object):
                     headers[k] = v.replace(text_to_replace, placeholder)
 
     def replace_in_body(self, text_to_replace, placeholder):
+        if text_to_replace == '':
+            return
         for obj in ('request', 'response'):
             body = self.data[obj]['body']
             old_style = hasattr(body, 'replace')
@@ -93,6 +97,8 @@ class Interaction(object):
                 self.data[obj]['body']['string'] = body
 
     def replace_in_uri(self, text_to_replace, placeholder):
+        if text_to_replace == '':
+            return
         for (obj, key) in (('request', 'uri'), ('response', 'url')):
             uri = self.data[obj][key]
             if text_to_replace in uri:


Test patch:
diff --git a/tests/unit/test_cassette.py b/tests/unit/test_cassette.py
index edd83d8..01ae406 100644
--- a/tests/unit/test_cassette.py
+++ b/tests/unit/test_cassette.py
@@ -443,6 +443,7 @@ class TestInteraction(unittest.TestCase):
         self.interaction.replace('secret_value', '<SECRET_VALUE>')
         self.interaction.replace('foo', '<FOO>')
         self.interaction.replace('http://example.com', '<EXAMPLE_URI>')
+        self.interaction.replace('', '<IF_FAIL_THIS_INSERTS_BEFORE_AND_AFTER_EACH_CHARACTER')
 
         header = (
             self.interaction.data['request']['headers']['Authorization'][0])