diff --git a/src/mapfile.py b/src/mapfile.py
index 0a0702ae88ee72416027ca3c2c953a1730b9d68c..bc7a1712ef4bbca3ea60dee1cc0bbf07d56a7023 100644
--- a/src/mapfile.py
+++ b/src/mapfile.py
@@ -37,6 +37,8 @@ import functools
 import maptools
 from webapp import KeyExists
 
+import tools
+
 class MetadataMixin(object):
 
     def __getattr__(self, attr):
@@ -55,7 +57,7 @@ def get_store_connection_string(info):
         url = urlparse.urlparse(cparam["url"])
         if url.scheme != "file" or url.netloc:
             raise ValueError("Only local files are suported.")
-        return url.path
+        return tools.get_resource_path(url.path)
     else:
         raise ValueError("Unhandled type '%s'" % cparam.get("dbtype", "<unknown>"))
 
@@ -316,9 +318,9 @@ class FeatureType(LayerModel):
         self.set_metadata("wfs_enable_request", "!GetCapabilities !DescribeFeatureType !GetFeature")
 
         # Update mra metadatas, and make sure the mandatory ones are left untouched.
+        self.update_mra_metadatas(metadata)
         self.update_mra_metadatas({"name": ft_name, "type": "featuretype", "storage": ds_name,
                                    "workspace": ws.name, "is_model": True})
-        self.update_metadatas(metadata)
 
     def configure_layer(self, layer, ws, enabled=True):
 
@@ -381,7 +383,6 @@ class Coverage(LayerModel):
     def update(self, ws, c_name, cs_name, metadata):
 
         cs = ws.get_coveragestore(cs_name)
-
         self.name = c_name
 
         # Set basic attributes.
@@ -410,9 +411,9 @@ class Coverage(LayerModel):
         self.set_metadata("wcs_enable_request", "!GetCapabilities !DescribeCoverage !GetCoverage")
 
         # Update mra metadatas, and make sure the mandatory ones are left untouched.
-        self.update_mra_metadatas({"name": cs_name, "type": "coverage", "storage": cs_name,
+        self.update_mra_metadatas(metadata)
+        self.update_mra_metadatas({"name": c_name, "type": "coverage", "storage": cs_name,
                                    "workspace": ws.name, "is_model": True})
-        self.update_metadatas(metadata)
 
     def configure_layer(self, layer, ws, enabled=True):
 
diff --git a/src/metadata.py b/src/metadata.py
index 5baaa62a437b71c8f4904a25b50f947f18706cff..398073806cfa5a1af6e01637b4c4b1347d8b7370 100644
--- a/src/metadata.py
+++ b/src/metadata.py
@@ -77,6 +77,7 @@ def set_metadatas(obj, metadatas):
         set_metadata(obj, key, value)
 
 def update_metadatas(obj, metadatas):
+    print metadatas
     for key, value in metadatas.iteritems():
         set_metadata(obj, key, value)
 
diff --git a/src/server.py b/src/server.py
index 2bb7fd4b0279eb60fb13aec2f06cb793ad87f9c5..028c3bf153761493f1a6d99704519ac1970a5733 100755
--- a/src/server.py
+++ b/src/server.py
@@ -56,7 +56,7 @@ class tests(object):
         tpath = tools.safe_path_join(get_config('storage')['mapfiles'], "%s.map" % name)
         open(tpath, "w").write(open(spath).read())
 
-        webapp.Created("%s/maps/%s.%s" % (web.ctx.home, name, format))
+        webapp.Created("%s/maps/%s%s" % (web.ctx.home, name, format))
 
 class mapfiles(object):
     @HTTPCompatible()
@@ -86,12 +86,12 @@ class mapfiles(object):
 
         return {"mapfiles": mapfiles}
 
-    def POST(self, map_name):
+    def POST(self, map_name, format):
         data = get_data()
 
         # TODO: Create mapfile
         raise NotImplemented()
-        webapp.Created("%s/maps/%s" % (web.ctx.home, map_name))
+        webapp.Created("%s/maps/%s%s" % (web.ctx.home, map_name, format))
 
 
 class named_mapfile(object):
@@ -157,8 +157,8 @@ class datastores(object):
             ws.create_datastore(ds_name, data)
         ws.save()
 
-        webapp.Created("%s/maps/%s/workspaces/%s/datastores/%s" % (
-                web.ctx.home, map_name, ws_name, ds_name))
+        webapp.Created("%s/maps/%s/workspaces/%s/datastores/%s%s" % (
+                web.ctx.home, map_name, ws_name, ds_name, format))
 
 
 class datastore(object):
@@ -209,10 +209,11 @@ class featuretypes(object):
 
         data = get_data(name="featureType", mandatory=["name"])
         with webapp.mightConflict("featureType", datastore=ds_name):
-            ws.create_featuretype(data["name"], ds_name, data)
+            with webapp.mightNotFound("featureType", datastore=ds_name):
+                ws.create_featuretype(data["name"], ds_name, data)
         ws.save()
 
-        webapp.Created("%s/maps/%s/workspaces/%s/datastores/%s/featuretypes/%s.%s" % (
+        webapp.Created("%s/maps/%s/workspaces/%s/datastores/%s/featuretypes/%s%s" % (
                 web.ctx.home, map_name, ws.name, ds_name, data["name"], format))
 
 
@@ -237,9 +238,9 @@ class featuretype(object):
                         "name": map_name,
                         "href": "%s/maps/%s/namespaces/%s.%s" % (web.ctx.home, map_name, ws_name, format)
                         },
-                    "title": ft.get_metadata("title", ft.name),
-                    "abstract": ft.get_metadata("abstract", None),
-                    "keywords": ft.get_metadata("keywords", []),
+                    "title": ft.get_mra_metadata("title", ft.name),
+                    "abstract": ft.get_mra_metadata("abstract", None),
+                    "keywords": ft.get_mra_metadata("keywords", []),
                     "srs": dsft.get_projection(),
                     "nativeCRS": dsft.get_native(),
                     "attributes": [{
@@ -282,8 +283,10 @@ class featuretype(object):
         if ft_name != data["name"]:
             raise webapp.Forbidden("Can't change the name of a feature type.")
 
+        metadata = dict((k, v) for k, v in data.iteritems() if k in ["title", "abstract"])
+
         with webapp.mightNotFound("featureType", datastore=ds_name):
-            ws.update_featuretype(ft_name, ds_name, data)
+            ws.update_featuretype(ft_name, ds_name, metadata)
         ws.save()
 
     def DELETE(self, map_name, ws_name, ds_name, ft_name, format):
@@ -309,15 +312,15 @@ class coveragestores(object):
     def POST(self, map_name, ws_name, format):
         mf, ws = get_mapfile_workspace(map_name, ws_name)
 
-        data = get_data(name="coverageStore", mandatory=["name", "connectionParameters"])
+        data = get_data(name="coverageStore", mandatory=["name"])
         cs_name = data.pop("name")
 
         with webapp.mightConflict("coverageStore", workspace=ws_name):
             ws.create_coveragestore(cs_name, data)
         ws.save()
 
-        webapp.Created("%s/maps/%s/workspaces/%s/coveragestores/%s" % (
-                web.ctx.home, map_name, ws_name, cs_name))
+        webapp.Created("%s/maps/%s/workspaces/%s/coveragestores/%s%s" % (
+                web.ctx.home, map_name, ws_name, cs_name, format))
 
 
 class coveragestore(object):
@@ -335,7 +338,7 @@ class coveragestore(object):
     def PUT(self, map_name, ws_name, cs_name, format):
         mf, ws = get_mapfile_workspace(map_name, ws_name)
 
-        data = get_data(name="coverageStore", mandatory=["name", "type", "connectionParameters"], forbidden=["href"])
+        data = get_data(name="coverageStore", mandatory=["name"], forbidden=["href"])
         if cs_name != data.pop("name"):
             raise webapp.Forbidden("Can't change the name of a coverage store.")
 
@@ -371,7 +374,7 @@ class coverages(object):
             ws.create_coverage(data["name"], cs_name, data)
         ws.save()
 
-        webapp.Created("%s/maps/%s/workspaces/%s/coveragestores/%s/coverages/%s.%s" % (
+        webapp.Created("%s/maps/%s/workspaces/%s/coveragestores/%s/coverages/%s%s" % (
                 web.ctx.home, map_name, ws.name, cs_name, data["name"], format))
 
 
@@ -379,7 +382,8 @@ class coverage(object):
     @HTTPCompatible()
     def GET(self, map_name, ws_name, cs_name, c_name, format):
         mf, ws = get_mapfile_workspace(map_name, ws_name)
-        c = ws.get_coverage(c_name, cs_name)
+        with webapp.mightNotFound("coverage", coveragestore=cs_name):
+            c = ws.get_coverage(c_name, cs_name)
 
         with webapp.mightNotFound("coveragestore", workspace=ws_name):
             cs = ws.get_coveragestore(cs_name)
@@ -394,9 +398,9 @@ class coverage(object):
                         "name": map_name,
                         "href": "%s/maps/%s/namespaces/%s.%s" % (web.ctx.home, map_name, ws_name, format)
                         },
-                    "title": c.get_metadata("title", c.name),
-                    "abstract": c.get_metadata("abstract", None),
-                    "keywords": c.get_metadata("keywords", []),
+                    "title": c.get_mra_metadata("title", c.name),
+                    "abstract": c.get_mra_metadata("abstract", None),
+                    "keywords": c.get_mra_metadata("keywords", []),
                     "srs": cs.get_projection(),
                     "nativeBoundingBox": {
                         "minx": extent.minX(),
@@ -428,8 +432,11 @@ class coverage(object):
         if c_name != data["name"]:
             raise webapp.Forbidden("Can't change the name of a coverage.")
 
+
+        metadata = dict((k, v) for k, v in data.iteritems() if k in ["title", "abstract"])
+
         with webapp.mightNotFound("coverage", coveragestore=cs_name):
-            ws.update_coverage(c_name, cs_name, data)
+            ws.update_coverage(c_name, cs_name, metadata)
         ws.save()
 
     def DELETE(self, map_name, ws_name, cs_name, c_name, format):
@@ -631,7 +638,7 @@ class layers(object):
             model.create_layer(ws, mf, l_name, l_enabled)
         mf.save()
 
-        webapp.Created("%s/maps/%s/layers/%s" % (web.ctx.home, map_name, l_name))
+        webapp.Created("%s/maps/%s/layers/%s%s" % (web.ctx.home, map_name, l_name, format))
 
 
 class layer(object):
@@ -747,7 +754,7 @@ class layerstyles(object):
         layer.add_style_sld(mf, s_name, style)
         mf.save()
 
-        webapp.Created("%s/maps/%s/layers/%s/layerstyles/%s" % (web.ctx.home, map_name, l_name, s_name))
+        webapp.Created("%s/maps/%s/layers/%s/layerstyles/%s%s" % (web.ctx.home, map_name, l_name, s_name, format))
 
 
 class layerstyle(object):
@@ -798,7 +805,7 @@ class layergroups(object):
 
         mf.save()
 
-        webapp.Created("%s/maps/%s/layergroups/%s" % (web.ctx.home, map_name, lg.name))
+        webapp.Created("%s/maps/%s/layergroups/%s%s" % (web.ctx.home, map_name, lg.name, format))
 
 
 class layergroup(object):
@@ -907,14 +914,13 @@ urlmap(layergroup, "maps", (), "layergroups", ())
 
 urls = tuple(urlmap)
 
-if get_config("debug")["web_debug"]:
-    web.config.debug = True
-if get_config("logging")["web_logs"]:
-    HTTPCompatible.return_logs = True
+web.config.debug = get_config("debug")["web_debug"]
+webapp.exceptionManager.raise_all = get_config("debug")["raise_all"]
+HTTPCompatible.return_logs = get_config("logging")["web_logs"]
 
 app = web.application(urls, globals())
 
 if __name__ == "__main__":
     app.run()
-
+u
 application = app.wsgifunc()
diff --git a/src/stores.py b/src/stores.py
index 1f359e372dbd0bae563a56f8bca80b658d916a80..f6d921039ac25804a17653bf588f56e422bf57da 100644
--- a/src/stores.py
+++ b/src/stores.py
@@ -324,7 +324,7 @@ class Datastore(object):
             if item == None: raise IndexError("No layer '%s'" % key)
         else:
             item = self.backend.GetLayerByName(key.encode('ascii', 'ignore'))
-            if item == None: raise KeyError("No layer '%s'" % key)
+            if item == None: raise KeyError(key)
         return Featuretype(item, self)
 
     def nblayers(self):
diff --git a/src/tools.py b/src/tools.py
index b336810ac27b15189c9ab8821d6b907733db642f..9751995d44b467299b30290342e327bec5049621 100644
--- a/src/tools.py
+++ b/src/tools.py
@@ -76,8 +76,11 @@ def safe_path_join(root, *args):
         raise webapp.Forbidden(message="path '%s' outside root directory." % (args))
     return full_path
 
+def get_resource_path(*args):
+    return safe_path_join(get_config('storage')['resources'], *args)
+
 def get_st_data_path(ws_name, st_type, name, *args):
-    return safe_path_join(get_config('storage')['resources'], "workspaces", ws_name, st_type, name, *args)
+    return get_resource_path("workspaces", ws_name, st_type, name, *args)
 
 def get_ds_data_path(ws_name, name, *args):
     return get_st_data_path(ws_name, "datastores", name, *args)
@@ -137,7 +140,7 @@ def no_root(root, path):
     return path[len(root):] if path.startswith(root) else path
 
 def no_res_root(path):
-    return no_root(get_config('storage')['resources'], path)
+    return os.path.relpath(path, get_config('storage')['resources'])
 
 def is_hidden(path):
     # TODO Add a lot of checks, recursive option (to check folders)
diff --git a/src/webapp.py b/src/webapp.py
index 778e81763169cfc1db6933cd27bdb97a2663b33d..1e4c41b8ac2c164466c9adab6b325e75bebe8c9b 100644
--- a/src/webapp.py
+++ b/src/webapp.py
@@ -113,6 +113,8 @@ class NotImplemented(web.webapi.HTTPError):
 # The folowing helpers are for managing exceptions and transforming them into http errors:
 
 class exceptionManager(object):
+    raise_all = False
+
     def __init__(self, exceptions):
         self.exceptions = exceptions
 
@@ -120,7 +122,7 @@ class exceptionManager(object):
         pass
 
     def __exit__(self, exc_type, exc_value, traceback):
-        if exc_type in self.exceptions:
+        if not self.raise_all and exc_type in self.exceptions:
             return not self.handle(exc_type, exc_value, traceback)
 
 
diff --git a/tests/files/HYP_LR.zip b/tests/files/HYP_LR.zip
new file mode 100644
index 0000000000000000000000000000000000000000..971e57da33e3b7e096c2292dbc73e7bd9558e024
Binary files /dev/null and b/tests/files/HYP_LR.zip differ
diff --git a/tests/testScenario.py b/tests/testScenario.py
index b82f0022b78174b80db934065d0105e931091ae5..7756ae1d000ecb1666ae03cd73b89e8361962cf7 100644
--- a/tests/testScenario.py
+++ b/tests/testScenario.py
@@ -48,6 +48,10 @@ def test_scenario():
     ws = APIRequest("GET", wss[0]["href"])["workspace"]
     assert ws["name"] == wss[0]["name"]
 
+    #
+    # Test DataStores.
+    #
+
     # GET dataStores
 
     dss = APIRequest("GET", ws["dataStores"]["href"])["dataStores"]
@@ -58,7 +62,7 @@ def test_scenario():
     name, title = "testDS1", "test datastore 1"
     _, r = APIRequest("POST", ws["dataStores"]["href"], {"dataStore":{"name":name, "title":title}},
                       get_response=True)
-    ds_link = r.getheader("Location")
+    ds_link = r.getheader("Location").split(".", 1)[0]
 
     ds = APIRequest("GET", ds_link)["dataStore"]
     assert ds["name"] == name
@@ -85,16 +89,108 @@ def test_scenario():
                encode=None, content_type="application/zip")
 
     ds = APIRequest("GET", ds_link)["dataStore"]
-    assert ds["connectionParameters"]["url"] == "file:/workspaces/%s/datastores/%s/timezones.shp" % (ws["name"], ds["name"])
+    assert ds["connectionParameters"]["url"] == "file:workspaces/%s/datastores/%s/timezones.shp" % (ws["name"], ds["name"])
 
-    # POST a featuretype
+    # POST a featuretype and GET it
 
-    name, title = "testFT1", "test feature type 1"
+    name, title = "timezones", "test feature type 1"
     _, r = APIRequest("POST", ds["href"], {"featureType":{"name":name, "title":title}},
                       get_response=True)
-    ft_link = r.getheader("Location")
+    ft_link = r.getheader("Location").split(".", 1)[0]
 
     ft = APIRequest("GET", ft_link)["featureType"]
     assert ft["name"] == name
-    assert ds["title"] == title
+    assert ft["title"] == title
+
+    # PUT a featuretype
+
+    ft["title"] = title.upper()
+    APIRequest("PUT", ft_link, {"featureType":ft})
+
+    ft = APIRequest("GET", ft_link)["featureType"]
+    assert ft["title"] == title.upper()
+
+    # DELETE stuff
+
+    APIRequest("DELETE", ft_link)
+    fts = APIRequest("GET", ds_link + "/featuretypes")["featureTypes"]
+    assert len(fts) == 0
+
+    APIRequest("DELETE", ds_link)
+    dss = APIRequest("GET", ws["dataStores"]["href"])["dataStores"]
+    assert len(dss) == 0
+
+
+
+    #
+    # Test CoverageStores.
+    #
+
+    # GET coverageStores
+
+    css = APIRequest("GET", ws["coverageStores"]["href"])["coverageStores"]
+    assert len(css) == 0
+
+    # POST a coverageStore and GET it
+
+    name, title = "testCS1", "test coverageStore 1"
+    _, r = APIRequest("POST", ws["coverageStores"]["href"], {"coverageStore":{"name":name, "title":title}},
+                      get_response=True)
+    cs_link = r.getheader("Location").split(".", 1)[0]
+
+    cs = APIRequest("GET", cs_link)["coverageStore"]
+    assert cs["name"] == name
+    assert cs["title"] == title
+
+    # PUT a coverageStore
+
+    cs["title"] = title.upper()
+    del cs["href"]
+    APIRequest("PUT", cs_link, {"coverageStore":cs})
+
+    cs = APIRequest("GET", cs_link)["coverageStore"]
+    assert cs["title"] == title.upper()
+
+    # GET coverages
+
+    fts = APIRequest("GET", cs["href"])["coverages"]
+    assert len(fts) == 0
+
+
+    # PUT file, and check if coverageStore is updated.
+
+    APIRequest("PUT", cs_link + "/file.tif", open("./files/HYP_LR.zip", "rb"),
+               encode=None, content_type="application/zip")
+
+    cs = APIRequest("GET", cs_link)["coverageStore"]
+    assert cs["connectionParameters"]["url"] == "file:workspaces/%s/coveragestores/%s/HYP_LR/HYP_LR.tif" % (ws["name"], cs["name"])
+
+    # POST a coverage and GET it
+
+    name, title = "HYP_LR", "test coverage 1"
+    _, r = APIRequest("POST", cs["href"], {"coverage":{"name":name, "title":title}},
+                      get_response=True)
+    ft_link = r.getheader("Location").split(".", 1)[0]
+
+    ft = APIRequest("GET", ft_link)["coverage"]
+    assert ft["name"] == name
+    assert ft["title"] == title
+
+    # PUT a coverage
+
+    ft["title"] = title.upper()
+    APIRequest("PUT", ft_link, {"coverage":ft})
+
+    ft = APIRequest("GET", ft_link)["coverage"]
+    assert ft["title"] == title.upper()
+
+    # DELETE stuff
+
+    APIRequest("DELETE", ft_link)
+    fts = APIRequest("GET", cs_link + "/coverages")["coverages"]
+    assert len(fts) == 0
+
+    APIRequest("DELETE", cs_link)
+    css = APIRequest("GET", ws["coverageStores"]["href"])["coverageStores"]
+    assert len(css) == 0