Пример #1
0
def test_etag_generation():
    from tiddlyweb.web.util import tiddler_etag
    from tiddlyweb.model.bag import Bag
    from tiddlyweb.model.tiddler import Tiddler
    from tiddlyweb.config import config

    tiddler = Tiddler('monkey', 'bar')
    etag = tiddler_etag({'tiddlyweb.config': config}, tiddler)

    assert etag.startswith('"bar/monkey/0:')

    bag = Bag('bar')
    store.put(bag)
    store.put(tiddler)
    etag = tiddler_etag({'tiddlyweb.config': config}, tiddler)
    assert etag.startswith('"bar/monkey/1:')
Пример #2
0
def validate_tiddler_headers(environ, tiddler):
    """
    Check ETAG and last modified information to
    see if a) the client can use its cached tiddler
    b) we have edit contention when trying to write.
    """
    request_method = environ['REQUEST_METHOD']
    tiddlers_etag = tiddler_etag(environ, tiddler)

    LOGGER.debug('attempting to validate %s with revision %s',
            tiddler.title.encode('utf-8'), tiddler.revision)

    etag = None
    last_modified = None
    if request_method == 'GET':
        incoming_etag = check_incoming_etag(environ, tiddlers_etag)
        if not incoming_etag:  # only check last-modified if no etag
            last_modified_string = http_date_from_timestamp(
                    tiddler.modified)
            last_modified = ('Last-Modified', last_modified_string)
            check_last_modified(environ, last_modified_string)

    else:
        incoming_etag = environ.get('HTTP_IF_MATCH', None)
        LOGGER.debug('attempting to validate incoming etag(PUT):'
            '%s against %s', incoming_etag, tiddlers_etag)
        if incoming_etag and not _etag_write_match(incoming_etag,
                tiddlers_etag):
            raise HTTP412('Provided ETag does not match. '
                'Server content probably newer.')
    etag = ('Etag', '%s' % tiddlers_etag)
    return last_modified, etag
Пример #3
0
def test_etag_generation():
    from tiddlyweb.web.util import tiddler_etag
    from tiddlyweb.model.bag import Bag
    from tiddlyweb.model.tiddler import Tiddler
    from tiddlyweb.config import config

    tiddler = Tiddler('monkey', 'bar')
    etag = tiddler_etag({'tiddlyweb.config': config}, tiddler)

    assert etag.startswith('"bar/monkey/0:')

    bag = Bag('bar')
    store.put(bag)
    store.put(tiddler)
    etag = tiddler_etag({'tiddlyweb.config': config}, tiddler)
    assert etag.startswith('"bar/monkey/1:')
Пример #4
0
Файл: wiki.py Проект: pads/tank
def editor(environ, start_response, extant_tiddler=None, message=''):
    store = environ['tiddlyweb.store']
    usersign = environ['tiddlyweb.usersign']
    query = environ['tiddlyweb.query']
    config = environ['tiddlyweb.config']

    if extant_tiddler:
        tiddler = extant_tiddler
    else:
        bag_name = query['bag'][0]
        tiddler_title = query['tiddler'][0]

        if not (bag_name and tiddler_title):
            raise HTTP400('bad query: bag and tiddler required')

        bag = Bag(bag_name)
        try:
            bag = store.get(bag)
        except NoBagError:
            raise HTTP404('that tank does not exist')

        tiddler = Tiddler(tiddler_title, bag_name)
        tiddler_new = False
        try:
            tiddler = store.get(tiddler)
        except NoTiddlerError:
            tiddler.text = ''
            tiddler.type = 'text/x-markdown'
            tiddler_new = True

        if tiddler_new:
            bag.policy.allows(usersign, 'create')
        else:
            bag.policy.allows(usersign, 'write')

    edit_template = get_template(environ, EDIT_TEMPLATE)
    start_response('200 OK', [
        ('Content-Type', 'text/html; charset=UTF-8'),
        ('Cache-Control', 'no-cache')])
    return edit_template.generate({
        'socket_link': config.get('socket.link'),
        'csrf_token': get_nonce(environ),
        'gravatar': gravatar(environ),
        'message': message,
        'user': usersign['name'],
        'tiddler': tiddler,
        'etag': tiddler_etag(environ, tiddler).replace('"',
            '').split(':', 1)[0]
    })
Пример #5
0
    def _tiddler_as_div(self, tiddler):
        """
        Read in the tiddler from a div.
        """
        recipe_name = ''
        if tiddler.recipe:
            recipe_name = tiddler.recipe
        try:
            host = server_base_url(self.environ)
        except KeyError:
            host = ''
        host = '%s' % host

        if binary_tiddler(tiddler):
            tiddler_output = self._binary_tiddler(tiddler)
        else:
            tiddler_output = tiddler.text

        if tiddler.type == 'None' or not tiddler.type:
            tiddler.type = ''

        return ('<div title="%s" server.title="%s" server.page.revision="%s" '
                'server.etag="%s" '
                'modifier="%s" creator="%s" server.workspace="bags/%s" '
                'server.type="tiddlyweb" server.host="%s" '
                'server.recipe="%s" server.bag="%s" server.permissions="%s" '
                'server.content-type="%s" '
                'modified="%s" created="%s" tags="%s" %s>\n'
                '<pre>%s</pre>\n</div>\n' %
                    (escape_attribute_value(tiddler.title),
                        escape_attribute_value(tiddler.title),
                        tiddler.revision,
                        escape_attribute_value(tiddler_etag(
                            self.environ, tiddler)),
                        escape_attribute_value(tiddler.modifier),
                        escape_attribute_value(tiddler.creator),
                        escape_attribute_value(tiddler.bag),
                        host,
                        escape_attribute_value(recipe_name),
                        escape_attribute_value(tiddler.bag),
                        self._tiddler_permissions(tiddler),
                        tiddler.type,
                        tiddler.modified,
                        tiddler.created,
                        escape_attribute_value(self.tags_as(tiddler.tags)),
                        self._tiddler_fields(tiddler.fields),
                        html_encode(tiddler_output)))
Пример #6
0
def validate_tiddler_headers(environ, tiddler):
    """
    Check ETag and last modified header information to
    see if a) on ``GET`` the user agent can use its cached tiddler
    b) on ``PUT`` we have edit contention.
    """
    request_method = environ['REQUEST_METHOD']
    this_tiddlers_etag = tiddler_etag(environ, tiddler)

    LOGGER.debug('attempting to validate %s with revision %s', tiddler.title,
                 tiddler.revision)

    etag = None
    last_modified = None
    if request_method == 'GET':
        last_modified_string = http_date_from_timestamp(tiddler.modified)
        last_modified = ('Last-Modified', last_modified_string)
        cache_header = 'no-cache'
        if CACHE_CONTROL_FIELD in tiddler.fields:
            try:
                cache_header = 'max-age=%s' % int(
                    tiddler.fields[CACHE_CONTROL_FIELD])
            except ValueError:
                pass  # if the value is not an int use default header
        incoming_etag = check_incoming_etag(environ,
                                            this_tiddlers_etag,
                                            last_modified=last_modified_string,
                                            cache_control=cache_header)
        if not incoming_etag:  # only check last-modified if no etag
            check_last_modified(environ,
                                last_modified_string,
                                etag=this_tiddlers_etag,
                                cache_control=cache_header)

    else:
        incoming_etag = environ.get('HTTP_IF_MATCH', None)
        LOGGER.debug(
            'attempting to validate incoming etag(PUT):'
            '%s against %s', incoming_etag, this_tiddlers_etag)
        if incoming_etag and not _etag_write_match(incoming_etag,
                                                   this_tiddlers_etag):
            raise HTTP412('Provided ETag does not match. '
                          'Server content probably newer.')
    etag = ('ETag', '%s' % this_tiddlers_etag)
    return last_modified, etag
Пример #7
0
def editor(environ, start_response, extant_tiddler=None, message=''):
    store = environ['tiddlyweb.store']
    usersign = environ['tiddlyweb.usersign']
    query = environ['tiddlyweb.query']

    if extant_tiddler:
        tiddler = extant_tiddler
        bag = _fill_bag(store, Bag(tiddler.bag))
    else:
        try:
            bag_name = query['bag'][0]
            tiddler_title = query['tiddler'][0]
        except KeyError:
            raise HTTP400('bad query: bag and tiddler required')

        if not (bag_name and tiddler_title):
            raise HTTP400('bad query: bag and tiddler required')

        bag = _fill_bag(store, Bag(bag_name))

        tiddler = Tiddler(tiddler_title, bag_name)
        tiddler_new = False
        try:
            tiddler = store.get(tiddler)
        except NoTiddlerError:
            tiddler.text = ''
            tiddler.type = 'text/x-markdown'
            tiddler_new = True

        if tiddler_new:
            bag.policy.allows(usersign, 'create')
        else:
            bag.policy.allows(usersign, 'write')

    start_response('200 OK', [
        ('Content-Type', 'text/html; charset=UTF-8'),
        ('Cache-Control', 'no-cache')])
    return send_template(environ, EDIT_TEMPLATE, {
        'bag': bag,
        'message': message,
        'tiddler': tiddler,
        'etag': tiddler_etag(environ, tiddler).replace('"',
            '').split(':', 1)[0]
    })
Пример #8
0
def _validate_tiddler_headers(environ, tiddler):
    """
    Check ETAG and last modified information to
    see if a) the client can use its cached tiddler
    b) we have edit contention when trying to write.
    """
    request_method = environ['REQUEST_METHOD']
    tiddler_etag = web.tiddler_etag(environ, tiddler)

    logging.debug('attempting to validate %s with revision %s', tiddler.title,
                  tiddler.revision)

    etag = None
    last_modified = None
    if request_method == 'GET':
        incoming_etag = environ.get('HTTP_IF_NONE_MATCH', None)
        if incoming_etag:
            logging.debug(
                'attempting to validate incoming etag(GET):'
                '%s against %s', incoming_etag, tiddler_etag)
            if incoming_etag == tiddler_etag:
                raise HTTP304(incoming_etag)
        else:
            last_modified_string = web.http_date_from_timestamp(
                tiddler.modified)
            last_modified = ('Last-Modified', last_modified_string)
            incoming_modified = environ.get('HTTP_IF_MODIFIED_SINCE', None)
            if incoming_modified and \
                    (web.datetime_from_http_date(incoming_modified) >=
                            web.datetime_from_http_date(last_modified_string)):
                raise HTTP304('')

    else:
        incoming_etag = environ.get('HTTP_IF_MATCH', None)
        logging.debug(
            'attempting to validate incoming etag(PUT):'
            '%s against %s', incoming_etag, tiddler_etag)
        if incoming_etag and not _etag_write_match(incoming_etag,
                                                   tiddler_etag):
            raise HTTP412('Provided ETag does not match. '
                          'Server content probably newer.')
    etag = ('Etag', '%s' % tiddler_etag)
    return last_modified, etag
Пример #9
0
def validate_tiddler_headers(environ, tiddler):
    """
    Check ETag and last modified header information to
    see if a) on ``GET`` the user agent can use its cached tiddler
    b) on ``PUT`` we have edit contention.
    """
    request_method = environ['REQUEST_METHOD']
    this_tiddlers_etag = tiddler_etag(environ, tiddler)

    LOGGER.debug('attempting to validate %s with revision %s',
            tiddler.title, tiddler.revision)

    etag = None
    last_modified = None
    if request_method == 'GET':
        last_modified_string = http_date_from_timestamp(tiddler.modified)
        last_modified = ('Last-Modified', last_modified_string)
        cache_header = 'no-cache'
        if CACHE_CONTROL_FIELD in tiddler.fields:
            try:
                cache_header = 'max-age=%s' % int(
                        tiddler.fields[CACHE_CONTROL_FIELD])
            except ValueError:
                pass  # if the value is not an int use default header
        incoming_etag = check_incoming_etag(environ, this_tiddlers_etag,
                last_modified=last_modified_string,
                cache_control=cache_header)
        if not incoming_etag:  # only check last-modified if no etag
            check_last_modified(environ, last_modified_string,
                    etag=this_tiddlers_etag,
                    cache_control=cache_header)

    else:
        incoming_etag = environ.get('HTTP_IF_MATCH', None)
        LOGGER.debug('attempting to validate incoming etag(PUT):'
            '%s against %s', incoming_etag, this_tiddlers_etag)
        if incoming_etag and not _etag_write_match(incoming_etag,
                this_tiddlers_etag):
            raise HTTP412('Provided ETag does not match. '
                'Server content probably newer.')
    etag = ('ETag', '%s' % this_tiddlers_etag)
    return last_modified, etag
Пример #10
0
def _put_tiddler(environ, start_response, tiddler):
    """
    The guts of putting a tiddler into the store.

    There's a fair bit of special handling done here
    depending on whether the tiddler already exists or
    not.
    """
    store = environ['tiddlyweb.store']

    try:
        bag = Bag(tiddler.bag)
        _check_and_validate_tiddler(environ, bag, tiddler)

        user = environ['tiddlyweb.usersign']['name']
        if not user == 'GUEST':
            tiddler.modifier = user
        tiddler.modified = current_timestring()

        try:
            check_bag_constraint(environ, bag, 'accept')
        except (PermissionsError) as exc:
            _validate_tiddler_content(environ, tiddler)

        store.put(tiddler)
    except NoBagError as exc:
        raise HTTP409("Unable to put tiddler, %s. There is no bag named: "
                "%s (%s). Create the bag." %
                (tiddler.title, tiddler.bag, exc))
    except NoTiddlerError as exc:
        raise HTTP404('Unable to put tiddler, %s. %s' % (tiddler.title, exc))
    except TypeError as exc:
        raise HTTP409('Unable to put badly formed tiddler, %s:%s. %s'
                % (tiddler.bag, tiddler.title, exc))

    etag = ('ETag', tiddler_etag(environ, tiddler))
    response = [('Location', tiddler_url(environ, tiddler))]
    if etag:
        response.append(etag)
    start_response("204 No Content", response)

    return []
Пример #11
0
    def _tiddler_as_div(self, tiddler):
        """
        Read in the tiddler from a div.
        """
        recipe_name = ''
        if tiddler.recipe:
            recipe_name = tiddler.recipe
        try:
            host = server_base_url(self.environ)
        except KeyError:
            host = ''
        host = '%s' % host

        if binary_tiddler(tiddler):
            tiddler_output = self._binary_tiddler(tiddler)
        else:
            tiddler_output = tiddler.text

        if tiddler.type == 'None' or not tiddler.type:
            tiddler.type = ''

        return ('<div title="%s" server.title="%s" server.page.revision="%s" '
                'server.etag="%s" '
                'modifier="%s" creator="%s" server.workspace="bags/%s" '
                'server.type="tiddlyweb" server.host="%s" '
                'server.recipe="%s" server.bag="%s" server.permissions="%s" '
                'server.content-type="%s" '
                'modified="%s" created="%s" tags="%s" %s>\n'
                '<pre>%s</pre>\n</div>\n' %
                (escape_attribute_value(tiddler.title),
                 escape_attribute_value(tiddler.title), tiddler.revision,
                 escape_attribute_value(tiddler_etag(self.environ, tiddler)),
                 escape_attribute_value(
                     tiddler.modifier), escape_attribute_value(
                         tiddler.creator), escape_attribute_value(tiddler.bag),
                 host, escape_attribute_value(recipe_name),
                 escape_attribute_value(
                     tiddler.bag), self._tiddler_permissions(tiddler),
                 tiddler.type, tiddler.modified, tiddler.created,
                 escape_attribute_value(self.tags_as(
                     tiddler.tags)), self._tiddler_fields(
                         tiddler.fields), html_encode(tiddler_output)))
Пример #12
0
def _validate_tiddler_headers(environ, tiddler):
    """
    Check ETAG and last modified information to
    see if a) the client can use its cached tiddler
    b) we have edit contention when trying to write.
    """
    request_method = environ['REQUEST_METHOD']
    tiddler_etag = web.tiddler_etag(environ, tiddler)

    logging.debug('attempting to validate %s with revision %s',
            tiddler.title, tiddler.revision)

    etag = None
    last_modified = None
    if request_method == 'GET':
        incoming_etag = environ.get('HTTP_IF_NONE_MATCH', None)
        if incoming_etag:
            logging.debug('attempting to validate incoming etag(GET):'
                '%s against %s', incoming_etag, tiddler_etag)
            if incoming_etag == tiddler_etag:
                raise HTTP304(incoming_etag)
        else:
            last_modified_string = web.http_date_from_timestamp(
                    tiddler.modified)
            last_modified = ('Last-Modified', last_modified_string)
            incoming_modified = environ.get('HTTP_IF_MODIFIED_SINCE', None)
            if incoming_modified and \
                    (web.datetime_from_http_date(incoming_modified) >=
                            web.datetime_from_http_date(last_modified_string)):
                raise HTTP304('')

    else:
        incoming_etag = environ.get('HTTP_IF_MATCH', None)
        logging.debug('attempting to validate incoming etag(PUT):'
            '%s against %s', incoming_etag, tiddler_etag)
        if incoming_etag and not _etag_write_match(incoming_etag,
                tiddler_etag):
            raise HTTP412('Provided ETag does not match. '
                'Server content probably newer.')
    etag = ('Etag', '%s' % tiddler_etag)
    return last_modified, etag
Пример #13
0
def _put_tiddler(environ, start_response, tiddler):
    """
    The guts of putting a tiddler into the store.

    There's a fair bit of special handling done here
    depending on whether the tiddler already exists or
    not.
    """
    store = environ['tiddlyweb.store']

    try:
        bag = Bag(tiddler.bag)
        _check_and_validate_tiddler(environ, bag, tiddler)

        user = environ['tiddlyweb.usersign']['name']
        tiddler.modifier = user
        tiddler.modified = current_timestring()

        try:
            check_bag_constraint(environ, bag, 'accept')
        except (PermissionsError):
            _validate_tiddler_content(environ, tiddler)

        store.put(tiddler)
    except NoBagError as exc:
        raise HTTP409("Unable to put tiddler, %s. There is no bag named: "
                "%s (%s). Create the bag." %
                (tiddler.title, tiddler.bag, exc))
    except NoTiddlerError as exc:
        raise HTTP404('Unable to put tiddler, %s. %s' % (tiddler.title, exc))
    except TypeError as exc:
        raise HTTP409('Unable to put badly formed tiddler, %s:%s. %s'
                % (tiddler.bag, tiddler.title, exc))

    etag = ('ETag', tiddler_etag(environ, tiddler))
    response = [('Location', tiddler_url(environ, tiddler))]
    if etag:
        response.append(etag)
    start_response("204 No Content", response)

    return []
Пример #14
0
        tiddler.modified = current_timestring()

        try:
            _check_bag_constraint(environ, bag, 'accept')
        except (PermissionsError), exc:
            _validate_tiddler_content(environ, tiddler)

        store.put(tiddler)
    except NoBagError, exc:
        raise HTTP409("Unable to put tiddler, %s. There is no bag named: " \
                "%s (%s). Create the bag." %
                (tiddler.title, tiddler.bag, exc))
    except NoTiddlerError, exc:
        raise HTTP404('Unable to put tiddler, %s. %s' % (tiddler.title, exc))

    etag = ('Etag', web.tiddler_etag(environ, tiddler))
    response = [('Location', web.tiddler_url(environ, tiddler))]
    if etag:
        response.append(etag)
    start_response("204 No Content", response)

    return []


def _validate_tiddler_content(environ, tiddler):
    """
    Unless tiddler is valid raise a 409 with the reason why
    things to check are presumably tags and title, but we don't
    want to worry about that here, we want to dispatch elsewhere.
    """
    try:
Пример #15
0
def edit(environ, start_response):
    """
    XXX: Lots of duplication from editor.
    """
    store = environ['tiddlyweb.store']
    usersign = environ['tiddlyweb.usersign']
    query = environ['tiddlyweb.query']

    try:
        bag_name = query['bag'][0]
        title = query['title'][0]
        text = query['text'][0]
        tiddler_type = query['type'][0]
        tags = query['tags'][0]
        etag = query['etag'][0]
    except KeyError as exc:
        raise HTTP400('bad query: incomplete form, %s' % exc)

    tags = [tag.strip() for tag in tags.split(',')]

    if not (bag_name and title):
        raise HTTP400('bad query: bag and title required')

    bag = Bag(bag_name)
    try:
        bag = store.get(bag)
    except NoBagError:
        raise HTTP404('that tank does not exist')

    tiddler = Tiddler(title, bag_name)
    tiddler_new = False
    conflict = False
    try:
        tiddler = store.get(tiddler)
        existing_etag = tiddler_etag(environ, tiddler).replace('"',
                '').split(':', 1)[0]
        if etag != existing_etag:
            conflict = True
    except NoTiddlerError:
        tiddler.type = tiddler_type
        tiddler_new = True

    if tiddler_new:
        bag.policy.allows(usersign, 'create')
    else:
        bag.policy.allows(usersign, 'write')

    tiddler.text = text
    tiddler.tags = tags
    tiddler.modifier = usersign['name']
    tiddler.modified = current_timestring()

    if conflict:
        return editor(environ, start_response, tiddler,
                message='conflict')

    try:
        validate_tiddler(tiddler, environ)
    except InvalidTiddlerError as exc:
        return editor(environ, start_response, tiddler,
                message='Tiddler content is invalid: %s' % exc)

    store.put(tiddler)

    redirect_uri = tank_page_uri(environ, tiddler.bag, tiddler.title)

    start_response('303 See Other', [
        ('Location', str(redirect_uri))])

    return []
Пример #16
0
        tiddler.modified = current_timestring()

        try:
            _check_bag_constraint(environ, bag, 'accept')
        except (PermissionsError), exc:
            _validate_tiddler_content(environ, tiddler)

        store.put(tiddler)
    except NoBagError, exc:
        raise HTTP409("Unable to put tiddler, %s. There is no bag named: " \
                "%s (%s). Create the bag." %
                (tiddler.title, tiddler.bag, exc))
    except NoTiddlerError, exc:
        raise HTTP404('Unable to put tiddler, %s. %s' % (tiddler.title, exc))

    etag = ('Etag', web.tiddler_etag(environ, tiddler))
    response = [('Location', web.tiddler_url(environ, tiddler))]
    if etag:
        response.append(etag)
    start_response("204 No Content", response)

    return []


def _validate_tiddler_content(environ, tiddler):
    """
    Unless tiddler is valid raise a 409 with the reason why
    things to check are presumably tags and title, but we don't
    want to worry about that here, we want to dispatch elsewhere.
    """
    try: