summary refs log tree commit diff
diff options
context:
space:
mode:
authorKegan Dougal <kegan@matrix.org>2014-08-18 15:50:55 +0100
committerKegan Dougal <kegan@matrix.org>2014-08-18 17:18:54 +0100
commit35da1bf4a3ee6eeafec5965af05cefbb4bd3c0b5 (patch)
tree020fcae7d4ec3dd57022138c39a8af780839b247
parentAdded /matrix/content path, HS resource_for_content_repo attribute and FileUp... (diff)
downloadsynapse-35da1bf4a3ee6eeafec5965af05cefbb4bd3c0b5.tar.xz
Auth content uploads. Added a mapping function from request > filename. Added exception handling for content uploads. webclient: Only prefix the client API path on doRequest, not doBaseRequest (this would've broken the identity server auth too). Added matrixService.uploadContent. May not require mFileUpload anymore.
-rwxr-xr-xsynapse/app/homeserver.py2
-rw-r--r--synapse/http/server.py44
-rw-r--r--webclient/components/fileUpload/file-upload-service.js29
-rw-r--r--webclient/components/matrix/matrix-service.js18
4 files changed, 62 insertions, 31 deletions
diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py
index e5bd13a6eb..f7c1da9201 100755
--- a/synapse/app/homeserver.py
+++ b/synapse/app/homeserver.py
@@ -56,7 +56,7 @@ class SynapseHomeServer(HomeServer):
         return File("webclient")  # TODO configurable?
 
     def build_resource_for_content_repo(self):
-        return FileUploadResource("uploads")
+        return FileUploadResource("uploads", self.auth)
 
     def build_db_pool(self):
         """ Set up all the dbs. Since all the *.sql have IF NOT EXISTS, so we
diff --git a/synapse/http/server.py b/synapse/http/server.py
index f86151e51c..7d6e225e74 100644
--- a/synapse/http/server.py
+++ b/synapse/http/server.py
@@ -180,28 +180,48 @@ class RootRedirect(resource.Resource):
 class FileUploadResource(resource.Resource):
     isLeaf = True
 
-    def __init__(self, directory):
+    def __init__(self, directory, auth, file_map_func=None):
         resource.Resource.__init__(self)
         self.directory = directory
+        self.auth = auth
+        if not file_map_func:
+            file_map_func = self.map_request_to_name
+        self.get_name_for_request = file_map_func
+
+    @defer.inlineCallbacks
+    def map_request_to_name(self, request):
+        # auth the user
+        auth_user = yield self.auth.get_user_by_req(request)
+        logger.info("User %s is uploading a file.", auth_user)
+        defer.returnValue("boo2.png")
 
     def render(self, request):
         self._async_render(request)
         return server.NOT_DONE_YET
 
-    # @defer.inlineCallbacks
+    @defer.inlineCallbacks
     def _async_render(self, request):
-        request.setResponseCode(200)
-        request.setHeader(b"Content-Type", b"application/json")
+        try:
+            fname = yield self.get_name_for_request(request)
 
-        request.setHeader("Access-Control-Allow-Origin", "*")
-        request.setHeader("Access-Control-Allow-Methods",
-                          "GET, POST, PUT, DELETE, OPTIONS")
-        request.setHeader("Access-Control-Allow-Headers",
-                          "Origin, X-Requested-With, Content-Type, Accept")
+            with open(fname, "wb") as f:
+                f.write(request.content.read())
+
+            respond_with_json_bytes(request, 200,
+                                    json.dumps({"url": "not_implemented2"}),
+                                    send_cors=True)
 
-        request.write(json.dumps({"url": "not_implemented"}))
-        request.finish()
-        defer.succeed("not implemented")
+        except CodeMessageException as e:
+            logger.exception(e)
+            respond_with_json_bytes(request, e.code,
+                                    json.dumps(cs_exception(e)))
+        except Exception as e:
+            logger.error("Failed to store file: %s" % e)
+            respond_with_json_bytes(
+                request,
+                500,
+                json.dumps({"error": "Internal server error"}),
+                send_cors=True)
 
 
 def respond_with_json_bytes(request, code, json_bytes, send_cors=False):
diff --git a/webclient/components/fileUpload/file-upload-service.js b/webclient/components/fileUpload/file-upload-service.js
index 5729d5da48..0826666fe4 100644
--- a/webclient/components/fileUpload/file-upload-service.js
+++ b/webclient/components/fileUpload/file-upload-service.js
@@ -16,11 +16,12 @@
 
 'use strict';
 
+// TODO determine if this is really required as a separate service to matrixService.
 /*
  * Upload an HTML5 file to a server
  */
 angular.module('mFileUpload', [])
-.service('mFileUpload', ['$http', '$q', function ($http, $q) {
+.service('mFileUpload', ['matrixService', '$q', function (matrixService, $q) {
         
     /*
      * Upload an HTML5 file to a server and returned a promise
@@ -28,20 +29,18 @@ angular.module('mFileUpload', [])
      */
     this.uploadFile = function(file) {
         var deferred = $q.defer();
-        
-        // @TODO: This service runs with the do_POST hacky implementation of /synapse/demos/webserver.py.
-        // This is temporary until we have a true file upload service
-        console.log("Uploading " + file.name + "...");
-        $http.post(file.name, file)
-        .success(function(data, status, headers, config) {
-            deferred.resolve(location.origin + data.url);
-            console.log("   -> Successfully uploaded! Available at " + location.origin + data.url);
-        }).
-        error(function(data, status, headers, config) {
-            console.log("   -> Failed to upload"  + file.name);
-            deferred.reject();
-        });
+        console.log("Uploading " + file.name + "... to /matrix/content");
+        matrixService.uploadContent(file).then(
+            function(response) {
+                console.log("   -> Successfully uploaded! Available at " + location.origin + response.data.url);
+                deferred.resolve(location.origin + response.data.url);
+            },
+            function(error) {
+                console.log("   -> Failed to upload "  + file.name);
+                deferred.reject(error);
+            }
+        );
         
         return deferred.promise;
     };
-}]);
\ No newline at end of file
+}]);
diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js
index 47828993a1..b67beb007a 100644
--- a/webclient/components/matrix/matrix-service.js
+++ b/webclient/components/matrix/matrix-service.js
@@ -54,13 +54,14 @@ angular.module('matrixService', [])
         
         params.access_token = config.access_token;
         
+        if (path.indexOf(prefixPath) !== 0) {
+            path = prefixPath + path;
+        }
+        
         return doBaseRequest(config.homeserver, method, path, params, data, undefined);
     };
 
     var doBaseRequest = function(baseUrl, method, path, params, data, headers) {
-        if (path.indexOf(prefixPath) !== 0) {
-            path = prefixPath + path;
-        }
         return $http({
             method: method,
             url: baseUrl + path,
@@ -319,6 +320,17 @@ angular.module('matrixService', [])
             return doBaseRequest(config.identityServer, "POST", path, {}, data, headers); 
         },
         
+        uploadContent: function(file) {
+            var path = "/matrix/content";
+            var headers = {
+                "Content-Type": undefined // undefined means angular will figure it out
+            };
+            var params = {
+                access_token: config.access_token
+            };
+            return doBaseRequest(config.homeserver, "POST", path, params, file, headers);
+        },
+        
         // start listening on /events
         getEventStream: function(from, timeout) {
             var path = "/events";