def _process_request_body(environ, tiddler): """ Read request body to set tiddler content. If a serializer exists for the content type, use it, otherwise treat the content as binary or pseudo-binary tiddler. """ length, content_type = content_length_and_type(environ) content = read_request_body(environ, length) try: try: serialize_type = get_serialize_type(environ)[0] serializer = Serializer(serialize_type, environ) # Short circuit de-serialization attempt to avoid # decoding content multiple times. if hasattr(serializer.serialization, 'as_tiddler'): serializer.object = tiddler try: serializer.from_string(content.decode('utf-8')) except TiddlerFormatError as exc: raise HTTP400('unable to put tiddler: %s' % exc) else: raise NoSerializationError() except NoSerializationError: tiddler.type = content_type if pseudo_binary(tiddler.type): tiddler.text = content.decode('utf-8') else: tiddler.text = content except UnicodeDecodeError as exc: raise HTTP400('unable to decode tiddler, utf-8 expected: %s' % exc)
def from_special(uri, handle, mime=None): """ Import a binary or pseudo binary tiddler. If a mime is provided, set the type of the tiddler to that. Otherwise use the type determined by the URL handler. If a meta file is present and has a type, it will be used. This code is inspired by @bengillies bimport. """ title = _get_title_from_uri(uri) if mime: content_type = mime else: content_type = handle.headers['content-type'].split(';')[0] data = handle.read() meta_uri = '%s.meta' % uri try: meta_content = _get_url(meta_uri) tiddler = _from_text(title, meta_content + '\n\n') except (HTTPError, URLError, IOError, OSError): tiddler = Tiddler(title) if not tiddler.type and content_type: tiddler.type = content_type if pseudo_binary(tiddler.type): data = data.decode('utf-8', 'ignore') tiddler.text = data return tiddler
def _send_tiddler(environ, start_response, tiddler): """ Push a single tiddler out the network in the form of the chosen serialization. """ store = environ['tiddlyweb.store'] bag = Bag(tiddler.bag) # this will raise 403 if constraint does not pass try: check_bag_constraint(environ, bag, 'read') except NoBagError as exc: raise HTTP404('%s not found, no bag %s, %s' % (tiddler.title, tiddler.bag, exc)) try: tiddler = store.get(tiddler) except NoTiddlerError as exc: raise HTTP404('%s not found, %s' % (tiddler.title, exc)) # this will raise 304 # have to do this check after we read from the store because # we need the revision, which is sad last_modified, etag = validate_tiddler_headers(environ, tiddler) # make choices between binary or serialization content, mime_type, serialized = _get_tiddler_content(environ, tiddler) vary_header = ('Vary', 'Accept') cache_header = ('Cache-Control', 'no-cache') if CACHE_CONTROL_FIELD in tiddler.fields: try: cache_header = ('Cache-Control', 'max-age=%s' % int(tiddler.fields[CACHE_CONTROL_FIELD])) except ValueError: pass # if the value is not an int use default header # Add charset to pseudo_binary tiddler if not serialized and pseudo_binary(tiddler.type): mime_type = '%s; charset=UTF-8' % mime_type content_header = ('Content-Type', str(mime_type)) response = [cache_header, content_header, vary_header] if last_modified: response.append(last_modified) if etag: response.append(etag) start_response('200 OK', response) if isinstance(content, basestring) or isinstance(content, bytes): return [content] else: return content
def get_remote_tiddler_html(environ, uri, title): """ Retrieve a webpage as a tiddler. Type comes from content-type. Text is set to the body. TODO: use response metadata to set other attributes """ response, content = retrieve_remote(uri) tiddler = RemoteTiddler(title, uri) try: content_type = response['content-type'].split(';', 1)[0] except KeyError: content_type = 'text/html' if pseudo_binary(content_type): tiddler.text = content.decode('utf-8', 'replace') else: tiddler.text = content tiddler.type = content_type return tiddler
def closet(environ, start_response): """ Read file input and write it to special storage. """ store = environ['tiddlyweb.store'] usersign = environ['tiddlyweb.usersign'] bag_name = get_route_value(environ, 'bag_name') redir = environ['tiddlyweb.query'].get('redir', [False])[0] target_name = environ['tiddlyweb.query'].get('name', [None])[0] bag = store.get(Bag(bag_name)) bag.policy.allows(usersign, 'create') bag.policy.allows(usersign, 'write') files = environ['tiddlyweb.input_files'] if not files: raise HTTP400('missing file input') tiddlers = [] for input_file in files: if target_name is None: target_name = input_file.filename if pseudo_binary(input_file.type): tiddler = _regular_tiddler(environ, bag_name, input_file, target_name) else: tiddler = _binary_tiddler(environ, bag_name, input_file, target_name) tiddlers.append(tiddler) response_code = '303 See Other' if redir else '204 No Content' start_response(response_code, [('Location', tiddler_url(environ, tiddlers[-1]))]) return []
def closet(environ, start_response): """ Read file input and write it to special storage. """ store = environ['tiddlyweb.store'] usersign = environ['tiddlyweb.usersign'] bag_name = get_route_value(environ, 'bag_name') redir = environ['tiddlyweb.query'].get('redir', [False])[0] target_name = environ['tiddlyweb.query'].get('name', [None])[0] bag = store.get(Bag(bag_name)) bag.policy.allows(usersign, 'create') bag.policy.allows(usersign, 'write') files = environ['tiddlyweb.input_files'] if not files: raise HTTP400('missing file input') tiddlers = [] for input_file in files: if target_name is None: target_name = input_file.filename if pseudo_binary(input_file.type): tiddler = _regular_tiddler(environ, bag_name, input_file, target_name) else: tiddler = _binary_tiddler(environ, bag_name, input_file, target_name) tiddlers.append(tiddler) response_code = '303 See Other' if redir else '204 No Content' start_response(response_code, [ ('Location', tiddler_url(environ, tiddlers[-1]))]) return []
try: # XXX HACK! We don't want to decode content unless # the serializer has a as_tiddler. We should be able # to just rely on NoSerializationError, but we need # to call the method to do that, and to call the method we # need to decode the string... serialize_type = web.get_serialize_type(environ)[0] serializer = Serializer(serialize_type, environ) serializer.object = tiddler try: serializer.from_string(content.decode('utf-8')) except TiddlerFormatError, exc: raise HTTP400('unable to put tiddler: %s' % exc) except NoSerializationError: tiddler.type = content_type if pseudo_binary(tiddler.type): tiddler.text = content.decode('utf-8') else: tiddler.text = content except UnicodeDecodeError, exc: raise HTTP400('unable to decode tiddler, utf-8 expected: %s', exc) try: recipe_name = web.get_route_value(environ, 'recipe_name') recipe = Recipe(recipe_name) try: store = environ['tiddlyweb.store'] recipe = store.get(recipe) tiddler.recipe = recipe_name except NoRecipeError, exc: raise HTTP404('%s not found via recipe, %s' % (tiddler.title, exc))
try: serialize_type = get_serialize_type(environ)[0] serializer = Serializer(serialize_type, environ) # Short circuit de-serialization attempt to avoid # decoding content multiple times. if hasattr(serializer.serialization, 'as_tiddler'): serializer.object = tiddler try: serializer.from_string(content.decode('utf-8')) except TiddlerFormatError, exc: raise HTTP400('unable to put tiddler: %s' % exc) else: raise NoSerializationError() except NoSerializationError: tiddler.type = content_type if pseudo_binary(tiddler.type): tiddler.text = content.decode('utf-8') else: tiddler.text = content except UnicodeDecodeError, exc: raise HTTP400('unable to decode tiddler, utf-8 expected: %s', exc) def _check_and_validate_tiddler(environ, bag, tiddler): """ If the tiddler does not exist, check we have create in the bag. If the tiddler does exist, check we have edit. In either case, check ETag to be sure that if it is set, that it maches what is currently in the store. """