Example #1
0
def respond_404(request):
    respond_with_json(
        request,
        404,
        cs_error("Not found %r" % (request.postpath,), code=Codes.NOT_FOUND),
        send_cors=True,
    )
Example #2
0
    def _async_render_POST(self, request):
        requester = yield self.auth.get_user_by_req(request)
        # TODO: The checks here are a bit late. The content will have
        # already been uploaded to a tmp file at this point
        content_length = request.getHeader(b"Content-Length").decode('ascii')
        if content_length is None:
            raise SynapseError(
                msg="Request must specify a Content-Length", code=400
            )
        if int(content_length) > self.max_upload_size:
            raise SynapseError(
                msg="Upload request body is too large",
                code=413,
            )

        upload_name = parse_string(request, b"filename", encoding=None)
        if upload_name:
            try:
                upload_name = upload_name.decode('utf8')
            except UnicodeDecodeError:
                raise SynapseError(
                    msg="Invalid UTF-8 filename parameter: %r" % (upload_name),
                    code=400,
                )

        headers = request.requestHeaders

        if headers.hasHeader(b"Content-Type"):
            media_type = headers.getRawHeaders(b"Content-Type")[0].decode('ascii')
        else:
            raise SynapseError(
                msg="Upload request missing 'Content-Type'",
                code=400,
            )

        # if headers.hasHeader(b"Content-Disposition"):
        #     disposition = headers.getRawHeaders(b"Content-Disposition")[0]
        # TODO(markjh): parse content-dispostion

        content_uri = yield self.media_repo.create_content(
            media_type, upload_name, request.content,
            content_length, requester.user
        )

        logger.info("Uploaded content with URI %r", content_uri)

        respond_with_json(
            request, 200, {"content_uri": content_uri}, send_cors=True
        )
Example #3
0
    def _async_render_POST(self, request):
        requester = yield self.auth.get_user_by_req(request)
        # TODO: The checks here are a bit late. The content will have
        # already been uploaded to a tmp file at this point
        content_length = request.getHeader("Content-Length")
        if content_length is None:
            raise SynapseError(msg="Request must specify a Content-Length",
                               code=400)
        if int(content_length) > self.max_upload_size:
            raise SynapseError(
                msg="Upload request body is too large",
                code=413,
            )

        upload_name = parse_string(request, "filename")
        if upload_name:
            try:
                upload_name = upload_name.decode('UTF-8')
            except UnicodeDecodeError:
                raise SynapseError(
                    msg="Invalid UTF-8 filename parameter: %r" % (upload_name),
                    code=400,
                )

        headers = request.requestHeaders

        if headers.hasHeader("Content-Type"):
            media_type = headers.getRawHeaders(b"Content-Type")[0]
        else:
            raise SynapseError(
                msg="Upload request missing 'Content-Type'",
                code=400,
            )

        # if headers.hasHeader(b"Content-Disposition"):
        #     disposition = headers.getRawHeaders(b"Content-Disposition")[0]
        # TODO(markjh): parse content-dispostion

        content_uri = yield self.media_repo.create_content(
            media_type, upload_name, request.content, content_length,
            requester.user)

        logger.info("Uploaded content with URI %r", content_uri)

        respond_with_json(request,
                          200, {"content_uri": content_uri},
                          send_cors=True)
Example #4
0
 def wrapped_request_handler(self, request):
     try:
         yield request_handler(self, request)
     except CodeMessageException as e:
         logger.exception(e)
         respond_with_json(request,
                           e.code,
                           cs_exception(e),
                           send_cors=True)
     except:
         logger.exception(
             "Failed handle request %s.%s on %r",
             request_handler.__module__,
             request_handler.__name__,
             self,
         )
         respond_with_json(request,
                           500, {"error": "Internal server error"},
                           send_cors=True)
Example #5
0
 def wrapped_request_handler(self, request):
     try:
         yield request_handler(self, request)
     except CodeMessageException as e:
         logger.exception(e)
         respond_with_json(
             request, e.code, cs_exception(e), send_cors=True
         )
     except:
         logger.exception(
             "Failed handle request %s.%s on %r",
             request_handler.__module__,
             request_handler.__name__,
             self,
         )
         respond_with_json(
             request,
             500,
             {"error": "Internal server error"},
             send_cors=True
         )
Example #6
0
    def _async_render_POST(self, request):
        auth_user, client = yield self.auth.get_user_by_req(request)
        # TODO: The checks here are a bit late. The content will have
        # already been uploaded to a tmp file at this point
        content_length = request.getHeader("Content-Length")
        if content_length is None:
            raise SynapseError(
                msg="Request must specify a Content-Length", code=400
            )
        if int(content_length) > self.max_upload_size:
            raise SynapseError(
                msg="Upload request body is too large",
                code=413,
            )

        headers = request.requestHeaders

        if headers.hasHeader("Content-Type"):
            media_type = headers.getRawHeaders("Content-Type")[0]
        else:
            raise SynapseError(
                msg="Upload request missing 'Content-Type'",
                code=400,
            )

        # if headers.hasHeader("Content-Disposition"):
        #     disposition = headers.getRawHeaders("Content-Disposition")[0]
        # TODO(markjh): parse content-dispostion

        content_uri = yield self.create_content(
            media_type, None, request.content.read(),
            content_length, auth_user
        )

        respond_with_json(
            request, 200, {"content_uri": content_uri}, send_cors=True
        )
Example #7
0
    def _async_render_POST(self, request):
        try:
            auth_user, client = yield self.auth.get_user_by_req(request)
            # TODO: The checks here are a bit late. The content will have
            # already been uploaded to a tmp file at this point
            content_length = request.getHeader("Content-Length")
            if content_length is None:
                raise SynapseError(msg="Request must specify a Content-Length",
                                   code=400)
            if int(content_length) > self.max_upload_size:
                raise SynapseError(
                    msg="Upload request body is too large",
                    code=413,
                )

            headers = request.requestHeaders

            if headers.hasHeader("Content-Type"):
                media_type = headers.getRawHeaders("Content-Type")[0]
            else:
                raise SynapseError(
                    msg="Upload request missing 'Content-Type'",
                    code=400,
                )

            # if headers.hasHeader("Content-Disposition"):
            #     disposition = headers.getRawHeaders("Content-Disposition")[0]
            # TODO(markjh): parse content-dispostion

            content_uri = yield self.create_content(media_type, None,
                                                    request.content.read(),
                                                    content_length, auth_user)

            respond_with_json(request,
                              200, {"content_uri": content_uri},
                              send_cors=True)
        except CodeMessageException as e:
            logger.exception(e)
            respond_with_json(request, e.code, cs_exception(e), send_cors=True)
        except:
            logger.exception("Failed to store file")
            respond_with_json(request,
                              500, {"error": "Internal server error"},
                              send_cors=True)
Example #8
0
 async def _async_render_GET(self, request: SynapseRequest) -> None:
     await self.auth.get_user_by_req(request)
     respond_with_json(request, 200, self.limits_dict, send_cors=True)
Example #9
0
 def render_OPTIONS(self, request):
     request.setHeader(b"Allow", b"OPTIONS, GET")
     return respond_with_json(request, 200, {}, send_cors=True)
Example #10
0
 def _async_render_GET(self, request):
     yield self.auth.get_user_by_req(request)
     respond_with_json(request, 200, self.limits_dict)
Example #11
0
    def _async_render_POST(self, request):
        try:
            auth_user = yield self.auth.get_user_by_req(request)
            # TODO: The checks here are a bit late. The content will have
            # already been uploaded to a tmp file at this point
            content_length = request.getHeader("Content-Length")
            if content_length is None:
                raise SynapseError(msg="Request must specify a Content-Length",
                                   code=400)
            if int(content_length) > self.max_upload_size:
                raise SynapseError(
                    msg="Upload request body is too large",
                    code=413,
                )

            headers = request.requestHeaders

            if headers.hasHeader("Content-Type"):
                media_type = headers.getRawHeaders("Content-Type")[0]
            else:
                raise SynapseError(
                    msg="Upload request missing 'Content-Type'",
                    code=400,
                )

            #if headers.hasHeader("Content-Disposition"):
            #    disposition = headers.getRawHeaders("Content-Disposition")[0]
            # TODO(markjh): parse content-dispostion

            media_id = random_string(24)

            fname = self.filepaths.local_media_filepath(media_id)
            self._makedirs(fname)

            # This shouldn't block for very long because the content will have
            # already been uploaded at this point.
            with open(fname, "wb") as f:
                f.write(request.content.read())

            yield self.store.store_local_media(
                media_id=media_id,
                media_type=media_type,
                time_now_ms=self.clock.time_msec(),
                upload_name=None,
                media_length=content_length,
                user_id=auth_user,
            )
            media_info = {
                "media_type": media_type,
                "media_length": content_length,
            }

            yield self._generate_local_thumbnails(media_id, media_info)

            content_uri = "mxc://%s/%s" % (self.server_name, media_id)

            respond_with_json(request,
                              200, {"content_uri": content_uri},
                              send_cors=True)
        except CodeMessageException as e:
            logger.exception(e)
            respond_with_json(request, e.code, cs_exception(e), send_cors=True)
        except:
            logger.exception("Failed to store file")
            respond_with_json(request,
                              500, {"error": "Internal server error"},
                              send_cors=True)
Example #12
0
 async def _async_render_OPTIONS(self, request):
     respond_with_json(request, 200, {}, send_cors=True)
Example #13
0
    async def _async_render_POST(self, request: SynapseRequest) -> None:
        requester = await self.auth.get_user_by_req(request)
        raw_content_length = request.getHeader("Content-Length")
        if raw_content_length is None:
            raise SynapseError(msg="Request must specify a Content-Length",
                               code=400)
        try:
            content_length = int(raw_content_length)
        except ValueError:
            raise SynapseError(msg="Content-Length value is invalid", code=400)
        if content_length > self.max_upload_size:
            raise SynapseError(
                msg="Upload request body is too large",
                code=413,
                errcode=Codes.TOO_LARGE,
            )

        args: Dict[bytes, List[bytes]] = request.args  # type: ignore
        upload_name_bytes = parse_bytes_from_args(args, "filename")
        if upload_name_bytes:
            try:
                upload_name: Optional[str] = upload_name_bytes.decode("utf8")
            except UnicodeDecodeError:
                raise SynapseError(
                    msg="Invalid UTF-8 filename parameter: %r" %
                    (upload_name_bytes, ),
                    code=400,
                )

        # If the name is falsey (e.g. an empty byte string) ensure it is None.
        else:
            upload_name = None

        headers = request.requestHeaders

        if headers.hasHeader(b"Content-Type"):
            content_type_headers = headers.getRawHeaders(b"Content-Type")
            assert content_type_headers  # for mypy
            media_type = content_type_headers[0].decode("ascii")
        else:
            media_type = "application/octet-stream"

        # if headers.hasHeader(b"Content-Disposition"):
        #     disposition = headers.getRawHeaders(b"Content-Disposition")[0]
        # TODO(markjh): parse content-dispostion

        try:
            content: IO = request.content  # type: ignore
            content_uri = await self.media_repo.create_content(
                media_type, upload_name, content, content_length,
                requester.user)
        except SpamMediaException:
            # For uploading of media we want to respond with a 400, instead of
            # the default 404, as that would just be confusing.
            raise SynapseError(400, "Bad content")

        logger.info("Uploaded content with URI %r", content_uri)

        respond_with_json(request,
                          200, {"content_uri": content_uri},
                          send_cors=True)
Example #14
0
 async def handle_request(self, request):
     respond_with_json(request, 200, {"some_key": "some_value_sync"})
Example #15
0
 async def _async_render_OPTIONS(self, request: SynapseRequest) -> None:
     respond_with_json(request, 200, {}, send_cors=True)
Example #16
0
 def render_OPTIONS(self, request):
     respond_with_json(request, 200, {}, send_cors=True)
     return NOT_DONE_YET
Example #17
0
    async def query_keys(
        self,
        request: SynapseRequest,
        query: JsonDict,
        query_remote_on_cache_miss: bool = False,
    ) -> None:
        logger.info("Handling query for keys %r", query)

        store_queries = []
        for server_name, key_ids in query.items():
            if (self.federation_domain_whitelist is not None
                    and server_name not in self.federation_domain_whitelist):
                logger.debug("Federation denied with %s", server_name)
                continue

            if not key_ids:
                key_ids = (None, )
            for key_id in key_ids:
                store_queries.append((server_name, key_id, None))

        cached = await self.store.get_server_keys_json(store_queries)

        json_results: Set[bytes] = set()

        time_now_ms = self.clock.time_msec()

        # Note that the value is unused.
        cache_misses: Dict[str, Dict[str, int]] = {}
        for (server_name, key_id, _), key_results in cached.items():
            results = [(result["ts_added_ms"], result)
                       for result in key_results]

            if not results and key_id is not None:
                cache_misses.setdefault(server_name, {})[key_id] = 0
                continue

            if key_id is not None:
                ts_added_ms, most_recent_result = max(results)
                ts_valid_until_ms = most_recent_result["ts_valid_until_ms"]
                req_key = query.get(server_name, {}).get(key_id, {})
                req_valid_until = req_key.get("minimum_valid_until_ts")
                miss = False
                if req_valid_until is not None:
                    if ts_valid_until_ms < req_valid_until:
                        logger.debug(
                            "Cached response for %r/%r is older than requested"
                            ": valid_until (%r) < minimum_valid_until (%r)",
                            server_name,
                            key_id,
                            ts_valid_until_ms,
                            req_valid_until,
                        )
                        miss = True
                    else:
                        logger.debug(
                            "Cached response for %r/%r is newer than requested"
                            ": valid_until (%r) >= minimum_valid_until (%r)",
                            server_name,
                            key_id,
                            ts_valid_until_ms,
                            req_valid_until,
                        )
                elif (ts_added_ms + ts_valid_until_ms) / 2 < time_now_ms:
                    logger.debug(
                        "Cached response for %r/%r is too old"
                        ": (added (%r) + valid_until (%r)) / 2 < now (%r)",
                        server_name,
                        key_id,
                        ts_added_ms,
                        ts_valid_until_ms,
                        time_now_ms,
                    )
                    # We more than half way through the lifetime of the
                    # response. We should fetch a fresh copy.
                    miss = True
                else:
                    logger.debug(
                        "Cached response for %r/%r is still valid"
                        ": (added (%r) + valid_until (%r)) / 2 < now (%r)",
                        server_name,
                        key_id,
                        ts_added_ms,
                        ts_valid_until_ms,
                        time_now_ms,
                    )

                if miss:
                    cache_misses.setdefault(server_name, {})[key_id] = 0
                # Cast to bytes since postgresql returns a memoryview.
                json_results.add(bytes(most_recent_result["key_json"]))
            else:
                for _, result in results:
                    # Cast to bytes since postgresql returns a memoryview.
                    json_results.add(bytes(result["key_json"]))

        # If there is a cache miss, request the missing keys, then recurse (and
        # ensure the result is sent).
        if cache_misses and query_remote_on_cache_miss:
            await yieldable_gather_results(
                lambda t: self.fetcher.get_keys(*t),
                ((server_name, list(keys), 0)
                 for server_name, keys in cache_misses.items()),
            )
            await self.query_keys(request,
                                  query,
                                  query_remote_on_cache_miss=False)
        else:
            signed_keys = []
            for key_json_raw in json_results:
                key_json = json_decoder.decode(key_json_raw.decode("utf-8"))
                for signing_key in self.config.key.key_server_signing_keys:
                    key_json = sign_json(key_json,
                                         self.config.server.server_name,
                                         signing_key)

                signed_keys.append(key_json)

            response = {"server_keys": signed_keys}

            respond_with_json(request, 200, response, canonical_json=True)
Example #18
0
 def render_OPTIONS(self, request):
     respond_with_json(request, 200, {}, send_cors=True)
     return NOT_DONE_YET
 async def _async_render_OPTIONS(self, request: SynapseRequest) -> None:
     request.setHeader(b"Allow", b"OPTIONS, GET")
     respond_with_json(request, 200, {}, send_cors=True)