commit a4e9c19c8eead340c51eae58c991c027f486c343
Author: Christos Stavrakakis <cstavr@grnet.gr>
Date:   Thu Feb 20 17:53:23 2014 +0200

    plankton: Fix handling of HTTP headers
    
    Handle properly image properties that are passed through HTTP headers.
    We convert the request headers to image properties by unquoting them and
    then decoding them to Unicode objects using 'utf-8' encoding. Image keys
    are lowered and all punctuation characters are converted to underscore.
    Respectively, we convert image properties to HTTP headers by encoding
    them to bytestrings and then properly quoting them.

diff --git a/snf-cyclades-app/synnefo/plankton/views.py b/snf-cyclades-app/synnefo/plankton/views.py
index ab8aeb0..40d37f6 100644
--- a/snf-cyclades-app/synnefo/plankton/views.py
+++ b/snf-cyclades-app/synnefo/plankton/views.py
@@ -35,11 +35,11 @@ import json
 
 from logging import getLogger
 from string import punctuation
-from urllib import unquote
+from urllib import unquote, quote
 
 from django.conf import settings
 from django.http import HttpResponse
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_unicode, smart_str
 
 from snf_django.lib import api
 from snf_django.lib.api import faults
@@ -81,21 +81,39 @@ log = getLogger('synnefo.plankton')
 
 
 def _create_image_response(image):
+    """Encode the image parameters to HTTP Response Headers.
+
+    Headers are encoded to UTF-8 then quoted.
+
+    """
     response = HttpResponse()
+    encode_header = lambda x: quote(smart_str(x, encoding='utf-8'))
 
     for key in DETAIL_FIELDS:
         if key == 'properties':
-            for k, v in image.get('properties', {}).items():
-                name = 'x-image-meta-property-' + k.replace('_', '-')
-                response[name] = smart_unicode(v, encoding="utf-8")
+            for pkey, pval in image.get('properties', {}).items():
+                pkey = 'http-x-image-meta-property-' + pkey.replace('_', '-')
+                pkey = quote(smart_str(pkey, encoding='utf-8'))
+                pval = quote(smart_str(pval, encoding='utf-8'))
+                response[encode_header(pkey)] = encode_header(pval)
         else:
-            name = 'x-image-meta-' + key.replace('_', '-')
-            response[name] = smart_unicode(image.get(key, ''), encoding="utf-8")
+            key = 'http-x-image-meta-' + key.replace('_', '-')
+            val = image.get('key', '')
+            response[encode_header(key)] = encode_header(val)
 
     return response
 
 
-def _get_image_headers(request):
+def headers_to_image_params(request):
+    """Decode the HTTP request headers to the acceptable image parameters.
+
+    Get image properties from the corresponding headers of the HTTP request.
+    Image headers are unquoted and then decoded to Unicode using UTF-8
+    encoding. Image headers keys are lowered and all punctation characters
+    are replaced with underscore.
+
+    """
+
     def normalize(s):
         return ''.join('_' if c in punctuation else c.lower() for c in s)
 
@@ -104,24 +122,26 @@ def _get_image_headers(request):
     META_PROPERTY_PREFIX = 'HTTP_X_IMAGE_META_PROPERTY_'
     META_PROPERTY_PREFIX_LEN = len(META_PROPERTY_PREFIX)
 
-    headers = {'properties': {}}
+    decode_header = lambda x: smart_unicode(unquote(x), encoding="utf-8")
+    is_img_property = lambda x: x.startswith(META_PROPERTY_PREFIX)
+    is_img_param = lambda x: x.startswith(META_PREFIX)
 
+    params = {}
+    properties = {}
     for key, val in request.META.items():
-        if key.startswith(META_PROPERTY_PREFIX):
-            name = normalize(key[META_PROPERTY_PREFIX_LEN:])
-            headers['properties'][unquote(name)] = unquote(val)
-        elif key.startswith(META_PREFIX):
-            name = normalize(key[META_PREFIX_LEN:])
-            headers[unquote(name)] = unquote(val)
-
-    is_public = headers.get('is_public', None)
-    if is_public is not None:
-        headers['is_public'] = True if is_public.lower() == 'true' else False
+        if isinstance(val, basestring):
+            val = decode_header(val)
+        if is_img_property(key):
+            key = decode_header(key[META_PROPERTY_PREFIX_LEN:])
+            properties[normalize(key)] = val
+        elif is_img_param(key):
+            key = decode_header(key[META_PREFIX_LEN:])
+            params[normalize(key)] = val
 
-    if not headers['properties']:
-        del headers['properties']
+    if properties:
+        params['properties'] = properties
 
-    return headers
+    return params
 
 
 @api.api_method(http_method="POST", user_required=True, logger=log)
@@ -143,7 +163,7 @@ def add_image(request):
         instead of uploading the data.
     """
 
-    params = _get_image_headers(request)
+    params = headers_to_image_params(request)
     log.debug('add_image %s', params)
 
     if not set(params.keys()).issubset(set(ADD_FIELDS)):
@@ -378,7 +398,7 @@ def update_image(request, image_id):
         and status.
     """
 
-    meta = _get_image_headers(request)
+    meta = headers_to_image_params(request)
     log.debug('update_image %s', meta)
 
     if not set(meta.keys()).issubset(set(UPDATE_FIELDS)):
