Example #1
0
    def run(self):
        processing_start_time = time.time()

        self.root = "response"
        self.response = {}

        if not self.headers:
            return self.failure("Header 'host' required for all requests.")
        hostname = self.headers["host"].partition(":")[0]
        hostname_matches = re.findall("(\w+).(rapidrec.com|localhost)", hostname)
        if not hostname_matches:
            return self.failure(
                "Could not determine sitename.  Please use " + "[sitename].rapidrec.com for all requests."
            )
        else:
            self.sitename = hostname_matches[0][0]
        # Check the validity of the sitename
        try:
            self.sitename = filters.check_name(self.sitename, 32)
        except (filters.TypeError, filters.RangeError):
            return self.failure("Invalid site: %s" % self.sitename)
        # Check that the site exists by instantiating RapidRecSite
        try:
            rrsite = RapidRecSite(self.sitename)
        except RapidRecSite.ConnectionError:
            return self.failure("Unknown site: %s" % self.sitename)
        # Check the remote IP against the list of allowed IPs
        remoteip = self.request.getClientIP()
        # Break a comma-separated string into a list, with one tuple per IP ('IP', unused, 'cidr')
        try:
            iplist = str(rrsite.get_config_field("ip_allow")).split(",")
        except RapidRecSite.ConfigFieldNotFound:
            iplist = ["0.0.0.0/0"]
        while "" in iplist:
            iplist.remove("")
        iplist.append("127.0.0.1")
        if self.sitename.startswith("test"):
            iplist.append("68.9.232.69")  # for development only
        if not ipfilter.is_ip_in_list(remoteip, iplist):
            return self.failure("Access forbidden from your IP: %s is not in { %s }" % (remoteip, ", ".join(iplist)))
        # At this point, the request is considered authentic.
        # We now proceed to process the request.
        # Find the path list and query (if any) by breaking up the QUERY_STRING
        # (fullpath, unused, query) = self.path.partition('?')
        fullpath = self.path
        path = fullpath.split("/")
        # Remove empty strings from the path list caused
        # by duplicate and unnecessary slashes in the path
        while "" in path:
            path.remove("")
        depth = 0
        args = {}
        if self.method == "post":
            if "content-length" not in self.headers:
                return self.failure("content-length required when POSTing")
            self.contentLength = int(self.headers["content-length"])
            self.request.content.seek(0, 0)
            args["postdata"] = self.request.content.read(self.contentLength)
        elif self.method != "get":
            return self.failure("Method not supported. Only GET and POST operations are allowed.")
        objtypes = ["users", "items", "movies"]
        try:
            if len(path) <= depth:
                raise (res.errors.UnimplementedError)
            elif path[depth] == "config":
                # /config...
                depth += 1
                raise (res.errors.UnimplementedError)
            elif path[depth] in objtypes:
                # /objs...
                args["type"] = "user" if path[depth] == "users" else "item"
                depth += 1
                if len(path) <= depth:
                    # /objs
                    Handler = res.objs.Handler
                else:
                    # /objs/{obj}...
                    args["name"] = path[depth]
                    depth += 1
                    if len(path) <= depth:
                        # /objs/{obj}
                        Handler = res.obj.Handler
                    elif path[depth] in objtypes:
                        # /objs/{obj}/objs...
                        args["tgt_type"] = "user" if path[depth] == "users" else "item"
                        depth += 1
                        if len(path) <= depth:
                            # /objs/{obj}/objs
                            raise (res.errors.UnimplementedError)
                        else:
                            # /objs/{obj}/objs/{obj}...
                            args["tgt_name"] = path[depth]
                            depth += 1
                            if len(path) <= depth:
                                # /objs/{obj}/objs/{obj}
                                Handler = res.objobj.Handler
                            else:
                                # /objs/{obj}/objs/{obj}/{resource}...
                                args["resource"] = path[depth]
                                depth += 1
                                if len(path) <= depth:
                                    # /objs/{obj}/objs/{obj}/{resource}
                                    Handler = res.objobjres.Handler
                                else:
                                    # /objs/{obj}/objs/{obj}/{resource}/...
                                    raise (res.errors.UnsupportedError)
                    else:
                        # /objs/{obj}/resource
                        args["resource"] = path[depth]
                        depth += 1
                        if len(path) <= depth:
                            # /objs/{obj}/{resource}
                            Handler = res.objres.Handler
                        else:
                            # /objs/{obj}/{resource}/...
                            raise (res.errors.UnsupportedError)
            else:
                # /{not-supported}...
                raise (res.errors.UnsupportedError)
            # Here is where we actually service queries that look valid so far
            handler = Handler(rrsite, self.response, self.method, self.request.args, args)
            handler.run()
            xmlext.set_status(self.response, "OKAY", "Query completed successfully.")
        except res.errors.ContentLengthMissingError:
            xmlext.set_status(self.response, "ERROR", "Content-length missing.")
        except res.errors.MethodError:
            xmlext.set_status(self.response, "ERROR", "Method not supported.")
        except res.errors.QueryError:
            xmlext.set_status(self.response, "ERROR", "Invalid query.")
        except res.errors.UnsupportedError:
            xmlext.set_status(self.response, "ERROR", "Resource not supported.")
        except res.errors.UnimplementedError:
            xmlext.set_status(self.response, "ERROR", "Resource not implemented.")
        except res.errors.PostError:
            xmlext.set_status(self.response, "ERROR", "Could not understand request body.")
        except res.errors.IdError:
            xmlext.set_status(self.response, "ERROR", "Invalid user or item identifier.")
        except res.errors.UnknownError:
            xmlext.set_status(self.response, "ERROR", "Unknown Error.")

        processing_finish_time = time.time()
        processing_time_elapsed = processing_finish_time - processing_start_time
        treexml.insert_node(self.response, "system_usage", "%f" % processing_time_elapsed)
        # print response
        self.respXML()
        self.send(treexml.encode(self.root, self.response))
        return self.finishreq()