示例#1
0
def default_bucket(request):
    if request.method.lower() == 'options':
        path = request.path.replace('default', 'unknown')
        subrequest = build_request(request, {
            'method': 'OPTIONS',
            'path': path
        })
        return request.invoke_subrequest(subrequest)

    if Authenticated not in request.effective_principals:
        # Pass through the forbidden_view_config
        raise httpexceptions.HTTPForbidden()

    settings = request.registry.settings

    if asbool(settings['readonly']):
        raise httpexceptions.HTTPMethodNotAllowed()

    bucket_id = request.default_bucket_id
    path = request.path.replace('/buckets/default', '/buckets/%s' % bucket_id)
    querystring = request.url[(request.url.index(request.path) +
                               len(request.path)):]

    try:
        # If 'id' is provided as 'default', replace with actual bucket id.
        body = request.json
        body['data']['id'] = body['data']['id'].replace('default', bucket_id)
    except:
        body = request.body

    # Make sure bucket exists
    create_bucket(request, bucket_id)

    # Make sure the collection exists
    create_collection(request, bucket_id)

    subrequest = build_request(request, {
        'method': request.method,
        'path': path + querystring,
        'body': body,
    })
    subrequest.bound_data = request.bound_data

    try:
        response = request.invoke_subrequest(subrequest)
    except httpexceptions.HTTPException as error:
        is_redirect = error.status_code < 400
        if error.content_type == 'application/json' or is_redirect:
            response = reapply_cors(subrequest, error)
        else:
            # Ask the upper level to format the error.
            raise error
    return response
示例#2
0
def default_bucket(request):
    if request.method.lower() == 'options':
        path = request.path.replace('default', 'unknown')
        subrequest = build_request(request, {
            'method': 'OPTIONS',
            'path': path
        })
        return request.invoke_subrequest(subrequest)

    if Authenticated not in request.effective_principals:
        # Pass through the forbidden_view_config
        raise httpexceptions.HTTPForbidden()

    settings = request.registry.settings

    if asbool(settings['readonly']):
        raise httpexceptions.HTTPMethodNotAllowed()

    bucket_id = request.default_bucket_id

    # Implicit object creations.
    # Make sure bucket exists
    create_bucket(request, bucket_id)
    # Make sure the collection exists
    create_collection(request, bucket_id)

    path = request.path.replace('/buckets/default',
                                '/buckets/{}'.format(bucket_id))
    querystring = request.url[(request.url.index(request.path) +
                               len(request.path)):]
    try:
        # If 'id' is provided as 'default', replace with actual bucket id.
        body = request.json
        body['data']['id'] = body['data']['id'].replace('default', bucket_id)
    except:
        body = request.body or {"data": {}}
    subrequest = build_request(request, {
        'method': request.method,
        'path': path + querystring,
        'body': body,
    })
    subrequest.bound_data = request.bound_data

    try:
        response = request.invoke_subrequest(subrequest)
    except httpexceptions.HTTPException as error:
        is_redirect = error.status_code < 400
        if error.content_type == 'application/json' or is_redirect:
            response = reapply_cors(subrequest, error)
        else:
            # Ask the upper level to format the error.
            raise error
    return response
示例#3
0
def default_bucket(request):
    if request.method.lower() == "options":
        path = request.path.replace("default", "unknown")
        subrequest = build_request(request, {
            "method": "OPTIONS",
            "path": path
        })
        return request.invoke_subrequest(subrequest)

    if Authenticated not in request.effective_principals:
        # Pass through the forbidden_view_config
        raise httpexceptions.HTTPForbidden()

    settings = request.registry.settings

    if asbool(settings["readonly"]):
        raise httpexceptions.HTTPMethodNotAllowed()

    bucket_id = request.default_bucket_id

    # Implicit object creations.
    # Make sure bucket exists
    create_bucket(request, bucket_id)
    # Make sure the collection exists
    create_collection(request, bucket_id)

    path = request.path.replace("/buckets/default", f"/buckets/{bucket_id}")
    querystring = request.url[(request.url.index(request.path) +
                               len(request.path)):]
    try:
        # If 'id' is provided as 'default', replace with actual bucket id.
        body = request.json
        body["data"]["id"] = body["data"]["id"].replace("default", bucket_id)
    except Exception:
        body = request.body or {"data": {}}
    subrequest = build_request(request, {
        "method": request.method,
        "path": path + querystring,
        "body": body
    })
    subrequest.bound_data = request.bound_data

    try:
        response = request.invoke_subrequest(subrequest)
    except httpexceptions.HTTPException as error:
        is_redirect = error.status_code < 400
        if error.content_type == "application/json" or is_redirect:
            response = reapply_cors(subrequest, error)
        else:
            # Ask the upper level to format the error.
            raise error
    return response
示例#4
0
def notify_resource_event(request,
                          request_options,
                          matchdict,
                          resource_name,
                          parent_id,
                          record,
                          action,
                          old=None):
    """Helper that triggers resource events as real requests.
    """
    fakerequest = build_request(request, request_options)
    fakerequest.matchdict = matchdict
    fakerequest.bound_data = request.bound_data
    fakerequest.authn_type, fakerequest.selected_userid = PLUGIN_USERID.split(
        ":")
    fakerequest.current_resource_name = resource_name

    # When kinto-signer copies record from one place to another,
    # it simulates a resource event. Since kinto-attachment
    # prevents from updating attachment fields, it throws an error.
    # The following flag will disable the kinto-attachment check.
    # See https://github.com/Kinto/kinto-signer/issues/256
    # and https://bugzilla.mozilla.org/show_bug.cgi?id=1470812
    has_changed_attachment = (resource_name == "record"
                              and action == ACTIONS.UPDATE
                              and "attachment" in old and
                              old["attachment"] != record.get("attachment"))
    if has_changed_attachment:
        fakerequest._attachment_auto_save = True

    fakerequest.notify_resource_event(parent_id=parent_id,
                                      timestamp=record[FIELD_LAST_MODIFIED],
                                      data=record,
                                      action=action,
                                      old=old)
示例#5
0
def notify_resource_event(request, request_options, matchdict,
                          resource_name, parent_id, obj, action, old=None):
    """Helper that triggers resource events as real requests.
    """
    fakerequest = build_request(request, request_options)
    fakerequest.matchdict = matchdict
    fakerequest.bound_data = request.bound_data
    fakerequest.authn_type, fakerequest.selected_userid = PLUGIN_USERID.split(":")
    fakerequest.current_resource_name = resource_name

    # When kinto-signer copies record from one place to another,
    # it simulates a resource event. Since kinto-attachment
    # prevents from updating attachment fields, it throws an error.
    # The following flag will disable the kinto-attachment check.
    # See https://github.com/Kinto/kinto-signer/issues/256
    # and https://bugzilla.mozilla.org/show_bug.cgi?id=1470812
    has_changed_attachment = (
        resource_name == "record" and action == ACTIONS.UPDATE and
        "attachment" in old and old["attachment"] != obj.get("attachment"))
    if has_changed_attachment:
        fakerequest._attachment_auto_save = True

    fakerequest.notify_resource_event(parent_id=parent_id,
                                      timestamp=obj[FIELD_LAST_MODIFIED],
                                      data=obj,
                                      action=action,
                                      old=old)
示例#6
0
def default_bucket(request):
    if request.method.lower() == "options":
        path = request.path.replace("default", "unknown")
        subrequest = build_request(request, {"method": "OPTIONS", "path": path})
        return request.invoke_subrequest(subrequest)

    if Authenticated not in request.effective_principals:
        # Pass through the forbidden_view_config
        raise httpexceptions.HTTPForbidden()

    settings = request.registry.settings

    if asbool(settings["readonly"]):
        raise httpexceptions.HTTPMethodNotAllowed()

    bucket_id = request.default_bucket_id

    # Implicit object creations.
    # Make sure bucket exists
    create_bucket(request, bucket_id)
    # Make sure the collection exists
    create_collection(request, bucket_id)

    path = request.path.replace("/buckets/default", "/buckets/{}".format(bucket_id))
    querystring = request.url[(request.url.index(request.path) + len(request.path)) :]
    try:
        # If 'id' is provided as 'default', replace with actual bucket id.
        body = request.json
        body["data"]["id"] = body["data"]["id"].replace("default", bucket_id)
    except Exception:
        body = request.body or {"data": {}}
    subrequest = build_request(
        request, {"method": request.method, "path": path + querystring, "body": body}
    )
    subrequest.bound_data = request.bound_data

    try:
        response = request.invoke_subrequest(subrequest)
    except httpexceptions.HTTPException as error:
        is_redirect = error.status_code < 400
        if error.content_type == "application/json" or is_redirect:
            response = reapply_cors(subrequest, error)
        else:
            # Ask the upper level to format the error.
            raise error
    return response
示例#7
0
def resource_create_object(request, resource_cls, uri):
    """Implicitly create a resource (or fail silently).

    In the default bucket, the bucket and collection are implicitly
    created. This helper creates one of those resources using a
    simulated request and context that is appropriate for the
    resource. Also runs create events as though the resource were
    created in a subrequest.

    If the resource already exists, do nothing.

    """
    resource_name, matchdict = view_lookup(request, uri)

    # Build a fake request, mainly used to populate the create events that
    # will be triggered by the resource.
    fakerequest = build_request(request, {
        'method': 'PUT',
        'path': uri,
    })
    fakerequest.matchdict = matchdict
    fakerequest.bound_data = request.bound_data
    fakerequest.authn_type = request.authn_type
    fakerequest.selected_userid = request.selected_userid
    fakerequest.errors = request.errors
    fakerequest.current_resource_name = resource_name

    obj_id = matchdict['id']

    # Fake context, required to instantiate a resource.
    context = RouteFactory(fakerequest)
    context.resource_name = resource_name
    resource = resource_cls(fakerequest, context)

    # Check that provided id is valid for this resource.
    if not resource.model.id_generator.match(obj_id):
        error_details = {
            'location': 'path',
            'description': 'Invalid {} id'.format(resource_name)
        }
        raise_invalid(resource.request, **error_details)

    data = {'id': obj_id}
    try:
        obj = resource.model.create_record(data)
    except UnicityError as e:
        # The record already exists; skip running events
        return e.record

    # Since the current request is not a resource (but a straight Service),
    # we simulate a request on a resource.
    # This will be used in the resource event payload.
    resource.postprocess(obj, action=ACTIONS.CREATE)
    return obj
示例#8
0
def resource_create_object(request, resource_cls, uri):
    """Implicitly create a resource (or fail silently).

    In the default bucket, the bucket and collection are implicitly
    created. This helper creates one of those resources using a
    simulated request and context that is appropriate for the
    resource. Also runs create events as though the resource were
    created in a subrequest.

    If the resource already exists, do nothing.

    """
    resource_name, matchdict = view_lookup(request, uri)

    # Build a fake request, mainly used to populate the create events that
    # will be triggered by the resource.
    fakerequest = build_request(request, {
        'method': 'PUT',
        'path': uri,
    })
    fakerequest.matchdict = matchdict
    fakerequest.bound_data = request.bound_data
    fakerequest.authn_type = request.authn_type
    fakerequest.selected_userid = request.selected_userid
    fakerequest.errors = request.errors
    fakerequest.current_resource_name = resource_name

    obj_id = matchdict['id']

    # Fake context, required to instantiate a resource.
    context = RouteFactory(fakerequest)
    context.resource_name = resource_name
    resource = resource_cls(fakerequest, context)

    # Check that provided id is valid for this resource.
    if not resource.model.id_generator.match(obj_id):
        error_details = {
            'location': 'path',
            'description': 'Invalid {} id'.format(resource_name)
        }
        raise_invalid(resource.request, **error_details)

    data = {'id': obj_id}
    try:
        obj = resource.model.create_record(data)
    except UnicityError as e:
        # The record already exists; skip running events
        return e.record

    # Since the current request is not a resource (but a straight Service),
    # we simulate a request on a resource.
    # This will be used in the resource event payload.
    resource.postprocess(obj, action=ACTIONS.CREATE)
    return obj
示例#9
0
文件: batch.py 项目: glasserc/kinto
def post_batch(request):
    requests = request.validated['body']['requests']

    request.log_context(batch_size=len(requests))

    limit = request.registry.settings['batch_max_requests']
    if limit and len(requests) > int(limit):
        error_msg = 'Number of requests is limited to {}'.format(limit)
        request.errors.add('body', 'requests', error_msg)
        return

    if any([batch.path in req['path'] for req in requests]):
        error_msg = 'Recursive call on {} endpoint is forbidden.'.format(batch.path)
        request.errors.add('body', 'requests', error_msg)
        return

    responses = []

    for subrequest_spec in requests:
        subrequest = build_request(request, subrequest_spec)

        log_context = {**request.log_context(),
                       'path': subrequest.path,
                       'method': subrequest.method}
        try:
            # Invoke subrequest without individual transaction.
            resp, subrequest = request.follow_subrequest(subrequest,
                                                         use_tweens=False)
        except httpexceptions.HTTPException as e:
            # Since some request in the batch failed, we need to stop the parent request
            # through Pyramid's transaction manager. 5XX errors are already caught by
            # pyramid_tm's commit_veto
            # https://github.com/Kinto/kinto/issues/624
            if e.status_code == 409:
                request.tm.abort()

            if e.content_type == 'application/json':
                resp = e
            else:
                # JSONify raw Pyramid errors.
                resp = errors.http_error(e)

        subrequest_logger.info('subrequest.summary', extra=log_context)

        dict_resp = build_response(resp, subrequest)
        responses.append(dict_resp)

    return {
        'responses': responses
    }
示例#10
0
文件: batch.py 项目: zeroyou/kinto
def post_batch(request):
    requests = request.validated["body"]["requests"]

    request.log_context(batch_size=len(requests))

    limit = request.registry.settings["batch_max_requests"]
    if limit and len(requests) > int(limit):
        error_msg = f"Number of requests is limited to {limit}"
        request.errors.add("body", "requests", error_msg)
        return

    if any([batch.path in req["path"] for req in requests]):
        error_msg = f"Recursive call on {batch.path} endpoint is forbidden."
        request.errors.add("body", "requests", error_msg)
        return

    responses = []

    for subrequest_spec in requests:
        subrequest = build_request(request, subrequest_spec)

        log_context = {
            **request.log_context(),
            "path": subrequest.path,
            "method": subrequest.method,
        }
        try:
            # Invoke subrequest without individual transaction.
            resp, subrequest = request.follow_subrequest(subrequest,
                                                         use_tweens=False)
        except httpexceptions.HTTPException as e:
            # Since some request in the batch failed, we need to stop the parent request
            # through Pyramid's transaction manager. 5XX errors are already caught by
            # pyramid_tm's commit_veto
            # https://github.com/Kinto/kinto/issues/624
            if e.status_code == 409:
                request.tm.abort()

            if e.content_type == "application/json":
                resp = e
            else:
                # JSONify raw Pyramid errors.
                resp = errors.http_error(e)

        subrequest_logger.info("subrequest.summary", extra=log_context)

        dict_resp = build_response(resp, subrequest)
        responses.append(dict_resp)

    return {"responses": responses}
示例#11
0
文件: batch.py 项目: tighterman/kinto
def post_batch(request):
    requests = request.validated['body']['requests']
    batch_size = len(requests)

    limit = request.registry.settings['batch_max_requests']
    if limit and len(requests) > int(limit):
        error_msg = 'Number of requests is limited to %s' % limit
        request.errors.add('body', 'requests', error_msg)
        return

    if any([batch.path in req['path'] for req in requests]):
        error_msg = 'Recursive call on %s endpoint is forbidden.' % batch.path
        request.errors.add('body', 'requests', error_msg)
        return

    responses = []

    sublogger = logger.new()

    for subrequest_spec in requests:
        subrequest = build_request(request, subrequest_spec)

        sublogger.bind(path=subrequest.path,
                       method=subrequest.method)
        try:
            # Invoke subrequest without individual transaction.
            resp, subrequest = request.follow_subrequest(subrequest,
                                                         use_tweens=False)
        except httpexceptions.HTTPException as e:
            if e.content_type == 'application/json':
                resp = e
            else:
                # JSONify raw Pyramid errors.
                resp = errors.http_error(e)

        sublogger.bind(code=resp.status_code)
        sublogger.info('subrequest.summary')

        dict_resp = build_response(resp, subrequest)
        responses.append(dict_resp)

    # Rebing batch request for summary
    logger.bind(path=batch.path,
                method=request.method,
                batch_size=batch_size,
                agent=request.headers.get('User-Agent'),)

    return {
        'responses': responses
    }
示例#12
0
文件: batch.py 项目: DarkDare/kinto
def post_batch(request):
    requests = request.validated['requests']
    batch_size = len(requests)

    limit = request.registry.settings['batch_max_requests']
    if limit and len(requests) > int(limit):
        error_msg = 'Number of requests is limited to %s' % limit
        request.errors.add('body', 'requests', error_msg)
        return

    if any([batch.path in req['path'] for req in requests]):
        error_msg = 'Recursive call on %s endpoint is forbidden.' % batch.path
        request.errors.add('body', 'requests', error_msg)
        return

    responses = []

    sublogger = logger.new()

    for subrequest_spec in requests:
        subrequest = build_request(request, subrequest_spec)

        sublogger.bind(path=subrequest.path,
                       method=subrequest.method)
        try:
            # Invoke subrequest without individual transaction.
            resp, subrequest = request.follow_subrequest(subrequest,
                                                         use_tweens=False)
        except httpexceptions.HTTPException as e:
            if e.content_type == 'application/json':
                resp = e
            else:
                # JSONify raw Pyramid errors.
                resp = errors.http_error(e)

        sublogger.bind(code=resp.status_code)
        sublogger.info('subrequest.summary')

        dict_resp = build_response(resp, subrequest)
        responses.append(dict_resp)

    # Rebing batch request for summary
    logger.bind(path=batch.path,
                method=request.method,
                batch_size=batch_size,
                agent=request.headers.get('User-Agent'),)

    return {
        'responses': responses
    }
示例#13
0
def notify_resource_event(request, request_options, matchdict,
                          resource_name, parent_id, record, action, old=None):
    """Private helper that triggers resource events when the updater modifies
    the source and destination objects.
    """
    fakerequest = build_request(request, request_options)
    fakerequest.matchdict = matchdict
    fakerequest.bound_data = request.bound_data
    fakerequest.selected_userid = "kinto-signer"
    fakerequest.authn_type = "plugin"
    fakerequest.current_resource_name = resource_name
    fakerequest.notify_resource_event(parent_id=parent_id,
                                      timestamp=record[FIELD_LAST_MODIFIED],
                                      data=record,
                                      action=action,
                                      old=old)
示例#14
0
def resource_create_object(request, resource_cls, uri):
    """In the default bucket, the bucket and collection are implicitly
    created. This helper instantiate the resource and simulate a request
    with its RootFactory on the instantiated resource.
    :returns: the created object
    :rtype: dict
    """
    resource_name, matchdict = view_lookup(request, uri)

    # Build a fake request, mainly used to populate the create events that
    # will be triggered by the resource.
    fakerequest = build_request(request, {
        'method': 'PUT',
        'path': uri,
    })
    fakerequest.matchdict = matchdict
    fakerequest.bound_data = request.bound_data
    fakerequest.authn_type = request.authn_type
    fakerequest.selected_userid = request.selected_userid
    fakerequest.errors = request.errors
    fakerequest.current_resource_name = resource_name

    obj_id = matchdict['id']

    # Fake context, required to instantiate a resource.
    context = RouteFactory(fakerequest)
    context.resource_name = resource_name
    resource = resource_cls(fakerequest, context)

    # Check that provided id is valid for this resource.
    if not resource.model.id_generator.match(obj_id):
        error_details = {
            'location': 'path',
            'description': "Invalid %s id" % resource_name
        }
        raise_invalid(resource.request, **error_details)

    data = {'id': obj_id}
    try:
        obj = resource.model.create_record(data)
        # Since the current request is not a resource (but a straight Service),
        # we simulate a request on a resource.
        # This will be used in the resource event payload.
        resource.postprocess(data, action=ACTIONS.CREATE)
    except storage_exceptions.UnicityError as e:
        obj = e.record
    return obj
示例#15
0
文件: batch.py 项目: urohit011/kinto
def post_batch(request):
    requests = request.validated['body']['requests']

    request.log_context(batch_size=len(requests))

    limit = request.registry.settings['batch_max_requests']
    if limit and len(requests) > int(limit):
        error_msg = 'Number of requests is limited to {}'.format(limit)
        request.errors.add('body', 'requests', error_msg)
        return

    if any([batch.path in req['path'] for req in requests]):
        error_msg = 'Recursive call on {} endpoint is forbidden.'.format(
            batch.path)
        request.errors.add('body', 'requests', error_msg)
        return

    responses = []

    for subrequest_spec in requests:
        subrequest = build_request(request, subrequest_spec)

        log_context = {
            'path': subrequest.path,
            'method': subrequest.method,
            **request.log_context()
        }
        try:
            # Invoke subrequest without individual transaction.
            resp, subrequest = request.follow_subrequest(subrequest,
                                                         use_tweens=False)
        except httpexceptions.HTTPException as e:
            if e.content_type == 'application/json':
                resp = e
            else:
                # JSONify raw Pyramid errors.
                resp = errors.http_error(e)

        subrequest_logger.info('subrequest.summary', extra=log_context)

        dict_resp = build_response(resp, subrequest)
        responses.append(dict_resp)

    return {'responses': responses}
示例#16
0
def notify_resource_event(request,
                          request_options,
                          matchdict,
                          resource_name,
                          parent_id,
                          record,
                          action,
                          old=None):
    """Private helper that triggers resource events when the updater modifies
    the source and destination objects.
    """
    fakerequest = build_request(request, request_options)
    fakerequest.matchdict = matchdict
    fakerequest.bound_data = request.bound_data
    fakerequest.selected_userid = "kinto-signer"
    fakerequest.authn_type = "plugin"
    fakerequest.current_resource_name = resource_name
    fakerequest.notify_resource_event(parent_id=parent_id,
                                      timestamp=record[FIELD_LAST_MODIFIED],
                                      data=record,
                                      action=action,
                                      old=old)
示例#17
0
 def test_built_request_has_kinto_core_custom_methods(self):
     original = build_real_request({'PATH_INFO': '/foo'})
     request = build_request(original, {"path": "bar"})
     self.assertTrue(hasattr(request, 'current_service'))
示例#18
0
 def test_built_request_has_kinto_core_custom_methods(self):
     original = build_real_request({"PATH_INFO": "/foo"})
     request = build_request(original, {"path": "bar"})
     self.assertTrue(hasattr(request, "current_service"))