diff --git a/pb/__main__.py b/pb/__main__.py index 9ee6860..ab40692 100644 --- a/pb/__main__.py +++ b/pb/__main__.py @@ -40,7 +40,8 @@ port = os.environ.get('LISTEN_PORT', 10002) with app.app_context(): - add_indexes(db.get_db()) + pass + #add_indexes(db.get_db()) run_simple(host, int(port), app, use_reloader=True, diff --git a/pb/paste/views.py b/pb/paste/views.py index e54824d..22df5c1 100644 --- a/pb/paste/views.py +++ b/pb/paste/views.py @@ -29,6 +29,8 @@ StatusResponse, redirect) from pb.util import (absolute_url, get_host_name, highlight, parse_sunset, request_content, request_keys, rst) +from pb import storage +from pb.storage import apocrypha paste = Blueprint('paste', __name__) @@ -86,63 +88,19 @@ def allowed_headers(headers): yield key, value -@paste.route('/', namespace_only=True, methods=['POST']) @paste.route('/', methods=['POST']) -@paste.route('/', methods=['POST']) -def post(label=None, namespace=None): - stream, filename = request_content() +def post(): + stream, _ = request_content() if not stream: return StatusResponse("no post content", 400) - cur = model.get_digest(stream) - - args = {} - if filename: - args['mimetype'], _ = guess_type(filename) - - for key, value in request_keys('private', 'sunset'): - try: - if key == 'sunset': - args[key] = parse_sunset(value) - else: - args[key] = int(value) - except (ValueError, OverflowError): - return StatusResponse({ - "invalid request params": {key: value} - }, 400) - - if label: - label, _ = label - if len(label) == 1: - return StatusResponse("invalid label", 400) - args['label'] = label - if namespace: - host = get_host_name(request) - if not _auth_namespace(host): - return StatusResponse("invalid auth", 403) - label, _ = namespace - args.update(dict( - label=label, - namespace=host + status, label = apocrypha.write(stream.read()) + if status is storage.WRITE.CREATED: + return PasteResponse(dict( + url="/" + label )) - - headers = dict(allowed_headers(request.headers)) - args['headers'] = headers - - try: - paste = next(cur) - uuid = None - status = "already exists" - except StopIteration: - try: - paste = model.insert(stream, **args) - except errors.DuplicateKeyError: - return StatusResponse("label already exists.", 409) - invalidate(**paste) - uuid = str(UUID(hex=paste['_id'])) - status = "created" - - return PasteResponse(paste, status, filename, uuid) + else: + return StatusResponse("error", 500) def _namespace_kwargs(kwargs): @@ -253,55 +211,27 @@ def report(sid=None, sha1=None, label=None, namespace=None): return PasteResponse(paste, "found") -@paste.route('/', namespace_only=True) -@paste.route('//', namespace_only=True) -@paste.route('///', namespace_only=True) -@paste.route('//', namespace_only=True) -@paste.route('/') -@paste.route('//') -@paste.route('///') -@paste.route('//') -@paste.route('/') -@paste.route('//') -@paste.route('///') -@paste.route('//') -@paste.route('/') -@paste.route('//') -@paste.route('///') -@paste.route('//') -@paste.route('/') -@paste.route('//') -@paste.route('///') -@paste.route('//') -def get(sid=None, sha1=None, label=None, namespace=None, lexer=None, handler=None, formatter=None): - cur, name, path = _get_paste(model.get_content, sid, sha1, label, namespace) - - paste = next(cur) - if paste.get('sunset'): - max_age = parse_sunset(**paste) - datetime.utcnow() - request.max_age = max_age.seconds - - content = model._get(paste.get('content')) - - if paste.get('redirect'): - content = content.decode('utf-8') - return redirect(content, content) - - mimetype, _ = guess_type(name) - if not mimetype: - mimetype = paste.get('mimetype', 'text/plain') - - headers = paste.get('headers', {}) +@paste.route('/') +@paste.route('//') +@paste.route('///') +@paste.route('//') +def get(label, lexer=None, formatter=None, handler=None): + status, content = apocrypha.read(label) + if status is storage.READ.FOUND: + pass + elif status is storage.READ.NOT_FOUND: + return StatusResponse("not found", 404) + else: + return StatusResponse("error", 500) if lexer is not None: return highlight(content, lexer, formatter) - if handler is not None: + elif handler is not None: return _handler.get(handler, content, mimetype, path=path) - - response = BaseResponse(content, mimetype=mimetype) - response.headers.extend(headers) - - return response + else: + mimetype, _ = guess_type(label) + response = BaseResponse(content, mimetype=mimetype) + return response @paste.route('/', methods=['POST']) diff --git a/pb/responses.py b/pb/responses.py index d700cab..9e2d0c1 100644 --- a/pb/responses.py +++ b/pb/responses.py @@ -111,7 +111,7 @@ def __init__(self, paste, status=None, filename=None, uuid=None, code=None): self._paste = paste paste['status'] = status # hack self.uuid = uuid - self.url = any_url(paste, filename) + #self.url = any_url(paste, filename) code = code or (302 if request.args.get('r') else 200) super().__init__(dict(self), code) @@ -124,9 +124,9 @@ def _dump(self, obj): return super()._dump(obj) def __dir__(self): - return ['url', 'long', 'short', - 'uuid', 'status', 'label', 'sunset', - 'redirect', 'digest', 'namespace', 'date', 'size'] + return ['url']#, 'long', 'short', + #'uuid', 'status', 'label', 'sunset', + #'redirect', 'digest', 'namespace', 'date', 'size'] def __getattr__(self, name): if name in dir(self): diff --git a/pb/storage/__init__.py b/pb/storage/__init__.py new file mode 100644 index 0000000..4aaa34c --- /dev/null +++ b/pb/storage/__init__.py @@ -0,0 +1 @@ +from pb.storage.types import * diff --git a/pb/storage/apocrypha.py b/pb/storage/apocrypha.py new file mode 100644 index 0000000..f949ed1 --- /dev/null +++ b/pb/storage/apocrypha.py @@ -0,0 +1,45 @@ +from typing import * + +from contextlib import closing +from http import client +import ssl + +from pb.storage import types + +host = "localhost" +port = 10000 + +ssl_context = ssl.create_default_context() +ssl_context.check_hostname = False +ssl_context.verify_mode = ssl.CERT_NONE + +connect = lambda: client.HTTPSConnection(host, port, context=ssl_context) + + +def read(name: str) -> Tuple[types.READ, bytes]: + with closing(connect()) as connection: + connection.request( + method="GET", + url="/" + name, + ) + response = connection.getresponse() + if response.code == 200: + return types.READ.FOUND, response.read() + elif response.code == 404: + return types.READ.NOT_FOUND, b"" + else: + return types.READ.ERROR, b"" + + +def write(content: bytes) -> Tuple[types.READ, types.PasteLabel]: + with closing(connect()) as connection: + connection.request( + method="POST", + url="/", + body=content, + ) + response = connection.getresponse() + if response.code == 200: + return types.WRITE.CREATED, response.read().decode('utf-8') + else: + return types.WRITE.ERROR, "" diff --git a/pb/storage/types.py b/pb/storage/types.py new file mode 100644 index 0000000..e82d961 --- /dev/null +++ b/pb/storage/types.py @@ -0,0 +1,20 @@ +# common types that storage backends use to express state to views in a +# implementation-agnostic way + +from enum import Enum, auto + + +__all__ = ["READ", "WRITE"] + + +PasteLabel = str + +class READ(Enum): + FOUND = auto() + NOT_FOUND = auto() + ERROR = auto() + + +class WRITE(Enum): + CREATED = auto() + ERROR = auto()