diff --git a/Gruntfile.js b/Gruntfile.js
index 825d5e71c9e724341635a23941e12864e84005cd..b66fc9e3fb0ad04a8957d50c0b6b67951f454862 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -169,6 +169,7 @@ module.exports = function (grunt) {
           'src/jio.storage/uuidstorage.js',
           'src/jio.storage/memorystorage.js',
           'src/jio.storage/zipstorage.js',
+          'src/jio.storage/httpstorage.js',
           'src/jio.storage/dropboxstorage.js',
           'src/jio.storage/davstorage.js',
           'src/jio.storage/gdrivestorage.js',
diff --git a/src/jio.storage/httpstorage.js b/src/jio.storage/httpstorage.js
new file mode 100644
index 0000000000000000000000000000000000000000..1ca49afeb47ed3a4cc2b4991d0d17c1db6c16309
--- /dev/null
+++ b/src/jio.storage/httpstorage.js
@@ -0,0 +1,94 @@
+/*global RSVP, Blob*/
+/*jslint nomen: true*/
+(function (jIO, RSVP, Blob) {
+  "use strict";
+
+  function HttpStorage(spec) {
+    if (spec.hasOwnProperty('catch_error')) {
+      this._catch_error = spec.catch_error;
+    } else {
+      this._catch_error = false;
+    }
+  }
+
+  HttpStorage.prototype.get = function (id) {
+    var context = this;
+    return new RSVP.Queue()
+      .push(function () {
+        return jIO.util.ajax({
+          type: 'HEAD',
+          url: id
+        });
+      })
+      .push(undefined, function (error) {
+        if (context._catch_error) {
+          return error;
+        }
+        if ((error.target !== undefined) &&
+            (error.target.status === 404)) {
+          throw new jIO.util.jIOError("Cannot find url " + id, 404);
+        }
+        throw error;
+      })
+      .push(function (response) {
+
+        var key_list = ["Content-Disposition", "Content-Type", "Date",
+                        "Last-Modified", "Vary", "Cache-Control", "Etag",
+                        "Accept-Ranges", "Content-Range"],
+          i,
+          key,
+          value,
+          result = {};
+        result.Status = response.target.status;
+        for (i = 0; i < key_list.length; i += 1) {
+          key = key_list[i];
+          value = response.target.getResponseHeader(key);
+          if (value !== null) {
+            result[key] = value;
+          }
+        }
+        return result;
+      });
+  };
+
+  HttpStorage.prototype.allAttachments = function () {
+    return {enclosure: {}};
+  };
+
+  HttpStorage.prototype.getAttachment = function (id, name) {
+    var context = this;
+    if (name !== 'enclosure') {
+      throw new jIO.util.jIOError("Forbidden attachment: "
+                                  + id + " , " + name,
+                                  400);
+    }
+    return new RSVP.Queue()
+      .push(function () {
+        return jIO.util.ajax({
+          type: 'GET',
+          url: id,
+          dataType: "blob"
+        });
+      })
+      .push(undefined, function (error) {
+        if (context._catch_error) {
+          return error;
+        }
+        if ((error.target !== undefined) &&
+            (error.target.status === 404)) {
+          throw new jIO.util.jIOError("Cannot find url " + id, 404);
+        }
+        throw error;
+      })
+      .push(function (response) {
+        return new Blob(
+          [response.target.response || response.target.responseText],
+          {"type": response.target.getResponseHeader('Content-Type') ||
+                   "application/octet-stream"}
+        );
+      });
+  };
+
+  jIO.addStorage('http', HttpStorage);
+
+}(jIO, RSVP, Blob));
\ No newline at end of file
diff --git a/test/jio.storage/httpstorage.tests.js b/test/jio.storage/httpstorage.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..18403cd4ec043fac1c3d0b85de1af86aa3787359
--- /dev/null
+++ b/test/jio.storage/httpstorage.tests.js
@@ -0,0 +1,336 @@
+/*jslint nomen: true */
+/*global Blob, sinon*/
+(function (jIO, QUnit, Blob, sinon) {
+  "use strict";
+  var test = QUnit.test,
+    stop = QUnit.stop,
+    start = QUnit.start,
+    ok = QUnit.ok,
+    expect = QUnit.expect,
+    deepEqual = QUnit.deepEqual,
+    equal = QUnit.equal,
+    module = QUnit.module,
+    domain = "https://example.org";
+
+  /////////////////////////////////////////////////////////////////
+  // davStorage constructor
+  /////////////////////////////////////////////////////////////////
+  module("httpStorage.constructor");
+
+  test("default parameters", function () {
+    var jio = jIO.createJIO({
+      type: "http"
+    });
+
+    equal(jio.__type, "http");
+    deepEqual(jio.__storage._catch_error, false);
+  });
+
+  test("Storage store catch_error", function () {
+    var jio = jIO.createJIO({
+      type: "http",
+      catch_error: true
+    });
+
+    equal(jio.__type, "http");
+    deepEqual(jio.__storage._catch_error, true);
+  });
+
+  /////////////////////////////////////////////////////////////////
+  // httpStorage.get
+  /////////////////////////////////////////////////////////////////
+  module("httpStorage.get", {
+    setup: function () {
+
+      this.server = sinon.fakeServer.create();
+      this.server.autoRespond = true;
+      this.server.autoRespondAfter = 5;
+
+      this.jio = jIO.createJIO({
+        type: "http"
+      });
+    },
+    teardown: function () {
+      this.server.restore();
+      delete this.server;
+    }
+  });
+
+  test("get document", function () {
+    var id = domain + "/id1/";
+    this.server.respondWith("HEAD", id, [200, {
+      "Content-Type": "text/xml-foo"
+    }, '']);
+    stop();
+    expect(1);
+
+    this.jio.get(id)
+      .then(function (result) {
+        deepEqual(result, {
+          "Content-Type": "text/xml-foo",
+          "Status": 200
+        }, "Check document");
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("get document with a not expected status", function () {
+    var id = domain + "/id1/";
+    this.server.respondWith("HEAD", id, [500, {
+      "Content-Type": "text/xml-foo"
+    }, '']);
+    stop();
+    expect(1);
+
+    this.jio.get(id)
+      .then(function (result) {
+        ok(false, result);
+      })
+      .fail(function (error) {
+        equal(error.target.status, 500);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("get document with 404 status", function () {
+    var id = domain + "/id1/";
+
+    stop();
+    expect(3);
+
+    this.jio.get(id)
+      .then(function (result) {
+        ok(false, result);
+      })
+      .fail(function (error) {
+        ok(error instanceof jIO.util.jIOError);
+        equal(error.message, "Cannot find url " + id);
+        equal(error.status_code, 404);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("get document with a not expected status and catch error", function () {
+    var id = domain + "/id1/";
+    this.server.respondWith("HEAD", id, [500, {
+      "Content-Type": "text/xml-foo"
+    }, '']);
+
+    this.jio = jIO.createJIO({
+      type: "http",
+      catch_error: true
+    });
+
+    stop();
+    expect(1);
+
+    this.jio.get(id)
+      .then(function (result) {
+        deepEqual(result, {
+          "Content-Type": "text/xml-foo",
+          "Status": 500
+        }, "Check document");
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  /////////////////////////////////////////////////////////////////
+  // httpStorage.allAttachments
+  /////////////////////////////////////////////////////////////////
+  module("httpStorage.allAttachments", {
+    setup: function () {
+
+      this.server = sinon.fakeServer.create();
+      this.server.autoRespond = true;
+      this.server.autoRespondAfter = 5;
+
+      this.jio = jIO.createJIO({
+        type: "http"
+      });
+    },
+    teardown: function () {
+      this.server.restore();
+      delete this.server;
+    }
+  });
+
+  test("get document with attachment", function () {
+    stop();
+    expect(1);
+
+    this.jio.allAttachments('/id')
+      .then(function (result) {
+        deepEqual(result, {
+          enclosure: {}
+        }, "Check document");
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  /////////////////////////////////////////////////////////////////
+  // httpStorage.getAttachment
+  /////////////////////////////////////////////////////////////////
+  module("httpStorage.getAttachment", {
+    setup: function () {
+
+      this.server = sinon.fakeServer.create();
+      this.server.autoRespond = true;
+      this.server.autoRespondAfter = 5;
+
+      this.jio = jIO.createJIO({
+        type: "http"
+      });
+    },
+    teardown: function () {
+      this.server.restore();
+      delete this.server;
+    }
+  });
+
+  test("forbidden attachment", function () {
+    var id = domain + "/id1/";
+
+    stop();
+    expect(3);
+
+    this.jio.getAttachment(
+      id,
+      "attachment1"
+    )
+      .fail(function (error) {
+        ok(error instanceof jIO.util.jIOError);
+        equal(
+          error.message,
+          "Forbidden attachment: https://example.org/id1/ , attachment1"
+        );
+        equal(error.status_code, 400);
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("get attachment", function () {
+    var id = domain + "/id1/";
+
+    this.server.respondWith("GET", id, [200, {
+      "Content-Type": "text/xml-foo"
+    }, "foo\nbaré"]);
+
+    stop();
+    expect(3);
+
+    this.jio.getAttachment(id, 'enclosure')
+      .then(function (result) {
+        ok(result instanceof Blob, "Data is Blob");
+        deepEqual(result.type, "text/xml-foo", "Check mimetype");
+        return jIO.util.readBlobAsText(result);
+      })
+      .then(function (result) {
+        equal(result.target.result, "foo\nbaré",
+              "Attachment correctly fetched");
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+
+  test("get attachment with a not expected status", function () {
+    var id = domain + "/id1/";
+    this.server.respondWith("GET", id, [500, {
+      "Content-Type": "text/xml-foo"
+    }, '']);
+    stop();
+    expect(1);
+
+    this.jio.getAttachment(id, 'enclosure')
+      .then(function (result) {
+        ok(false, result);
+      })
+      .fail(function (error) {
+        equal(error.target.status, 500);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("get attachment with 404 status", function () {
+    var id = domain + "/id1/";
+
+    stop();
+    expect(3);
+
+    this.jio.getAttachment(id, 'enclosure')
+      .then(function (result) {
+        ok(false, result);
+      })
+      .fail(function (error) {
+        ok(error instanceof jIO.util.jIOError);
+        equal(error.message, "Cannot find url " + id);
+        equal(error.status_code, 404);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("get attachment with unexpected status and catch error", function () {
+    var id = domain + "/id1/";
+    this.server.respondWith("GET", id, [500, {
+      "Content-Type": "text/xml-foo"
+    }, 'foo\nbaré']);
+
+    this.jio = jIO.createJIO({
+      type: "http",
+      catch_error: true
+    });
+
+    stop();
+    expect(3);
+
+    this.jio.getAttachment(id, 'enclosure')
+      .then(function (result) {
+        ok(result instanceof Blob, "Data is Blob");
+        deepEqual(result.type, "text/xml-foo", "Check mimetype");
+        return jIO.util.readBlobAsText(result);
+      })
+      .then(function (result) {
+        equal(result.target.result, "foo\nbaré",
+              "Attachment correctly fetched");
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+}(jIO, QUnit, Blob, sinon));
diff --git a/test/tests.html b/test/tests.html
index d72908a44131a56327876941b756716c7e5e9e18..9c76b2d42961112958e23345c4af93b2edd027c0 100644
--- a/test/tests.html
+++ b/test/tests.html
@@ -51,6 +51,7 @@
   <script src="jio.storage/zipstorage.tests.js"></script>
   <script src="jio.storage/gdrivestorage.tests.js"></script>
   <script src="jio.storage/websqlstorage.tests.js"></script>
+  <script src="jio.storage/httpstorage.tests.js"></script>
   <!--script src="../lib/jquery/jquery.min.js"></script>
   <script src="../src/jio.storage/xwikistorage.js"></script>
   <script src="jio.storage/xwikistorage.tests.js"></script-->