Ejemplo n.º 1
0
def put_resource_data(resource_id):
    content_type = "application/octet-stream"
    if request.headers.get("Content-type"):
        content_type, _ = parse_header(request.headers["Content-type"])

    with db.cursor() as cur:
        cur.execute(
            """
        SELECT id, data_oid FROM "resource" WHERE id = %(id)s;
        """,
            dict(id=resource_id),
        )
        resource = cur.fetchone()

    if resource is None:
        raise NotFound()

    # todo: better use a streaming response here..?
    with db, db.cursor() as cur:
        lobj = db.lobject(oid=resource["data_oid"], mode="wb")
        lobj.seek(0)
        lobj.truncate()
        lobj.write(request.data)
        lobj.close()

        resource_hash = "sha1:" + hashlib.sha1(request.data).hexdigest()

        data = dict(id=resource_id, mimetype=content_type, mtime=datetime.datetime.utcnow(), hash=resource_hash)

        query = querybuilder.update("resource", data)
        cur.execute(query, data)

    return "", 200
Ejemplo n.º 2
0
def put_resource_data(resource_id):
    content_type = 'application/octet-stream'
    if request.headers.get('Content-type'):
        content_type, _ = parse_header(request.headers['Content-type'])

    with db.cursor() as cur:
        cur.execute(
            """
        SELECT id, data_oid FROM "resource" WHERE id = %(id)s;
        """, dict(id=resource_id))
        resource = cur.fetchone()

    if resource is None:
        raise NotFound()

    # todo: better use a streaming response here..?
    with db, db.cursor() as cur:
        lobj = db.lobject(oid=resource['data_oid'], mode='wb')
        lobj.seek(0)
        lobj.truncate()
        lobj.write(request.data)
        lobj.close()

        resource_hash = 'sha1:' + hashlib.sha1(request.data).hexdigest()

        data = dict(id=resource_id,
                    mimetype=content_type,
                    mtime=datetime.datetime.utcnow(),
                    hash=resource_hash)

        query = querybuilder.update('resource', data)
        cur.execute(query, data)

    return '', 200
Ejemplo n.º 3
0
def delete_resource_data(resource_id):
    with db.cursor() as cur:
        cur.execute(
            """
        SELECT id, data_oid FROM "resource" WHERE id = %(id)s;
        """, dict(id=resource_id))
        resource = cur.fetchone()

    # todo: better use a streaming response here..?
    with db:
        lobj = db.lobject(oid=resource['data_oid'], mode='wb')
        lobj.unlink()

    # Then, create a record for the metadata
    with db, db.cursor() as cur:
        query = querybuilder.delete('resource')
        cur.execute(query, dict(id=resource_id))

    db.commit()
    return '', 200
Ejemplo n.º 4
0
def _get_internal_resource_data(resource_id):
    """Get all data form an internally-stored resource"""

    # todo: improve this function to avoid keeping the whole thing in memory
    # todo: also, make this more generic (and move from here)

    with db, db.cursor() as cur:
        cur.execute("""
        SELECT id, mimetype, data_oid FROM "resource" WHERE id = %(id)s;
        """, dict(id=resource_id))
        resource = cur.fetchone()

    if resource is None:
        raise NotFound()

    with db:
        lobject = db.lobject(oid=resource['data_oid'], mode='rb')
        data = lobject.read()
        lobject.close()

    return data
Ejemplo n.º 5
0
def post_resource_index():
    """
    We got some data to be stored as a new resource.

    Then we want to return 201 + URL of the created resource in the
    Location: header.
    """

    content_type = "application/octet-stream"
    if request.headers.get("Content-type"):
        content_type, _ = parse_header(request.headers["Content-type"])

    # First, store the data in a PostgreSQL large object
    with db, db.cursor() as cur:
        lobj = db.lobject(oid=0, mode="wb")
        oid = lobj.oid
        lobj.write(request.data)
        lobj.close()

        resource_hash = "sha1:" + hashlib.sha1(request.data).hexdigest()

        data = dict(
            metadata="{}",
            auto_metadata="{}",
            mimetype=content_type,
            data_oid=oid,
            ctime=datetime.datetime.utcnow(),
            mtime=datetime.datetime.utcnow(),
            hash=resource_hash,
        )

        # Then, create a record for the metadata
        query = querybuilder.insert("resource", data)
        cur.execute(query, data)
        resource_id = cur.fetchone()[0]

    # Last, retun 201 + Location: header
    location = url_for(".get_resource_data", resource_id=resource_id)
    return "", 201, {"Location": location}
Ejemplo n.º 6
0
def delete_resource_data(resource_id):
    with db.cursor() as cur:
        cur.execute(
            """
        SELECT id, data_oid FROM "resource" WHERE id = %(id)s;
        """,
            dict(id=resource_id),
        )
        resource = cur.fetchone()

    # todo: better use a streaming response here..?
    with db:
        lobj = db.lobject(oid=resource["data_oid"], mode="wb")
        lobj.unlink()

    # Then, create a record for the metadata
    with db, db.cursor() as cur:
        query = querybuilder.delete("resource")
        cur.execute(query, dict(id=resource_id))

    db.commit()
    return "", 200
Ejemplo n.º 7
0
def post_resource_index():
    """
    We got some data to be stored as a new resource.

    Then we want to return 201 + URL of the created resource in the
    Location: header.
    """

    content_type = 'application/octet-stream'
    if request.headers.get('Content-type'):
        content_type, _ = parse_header(request.headers['Content-type'])

    # First, store the data in a PostgreSQL large object
    with db, db.cursor() as cur:
        lobj = db.lobject(oid=0, mode='wb')
        oid = lobj.oid
        lobj.write(request.data)
        lobj.close()

        resource_hash = 'sha1:' + hashlib.sha1(request.data).hexdigest()

        data = dict(metadata='{}',
                    auto_metadata='{}',
                    mimetype=content_type,
                    data_oid=oid,
                    ctime=datetime.datetime.utcnow(),
                    mtime=datetime.datetime.utcnow(),
                    hash=resource_hash)

        # Then, create a record for the metadata
        query = querybuilder.insert('resource', data)
        cur.execute(query, data)
        resource_id = cur.fetchone()[0]

    # Last, retun 201 + Location: header
    location = url_for('.get_resource_data', resource_id=resource_id)
    return '', 201, {'Location': location}
Ejemplo n.º 8
0
def serve_resource(resource_id, transfer_block_size=4096):
    """
    Serve resource data via HTTP, setting ETag and Last-Modified headers
    and honoring ``If-None-Match`` and ``If-modified-since`` headers.

    Currently supported features:

    - Set ``ETag`` header (to the hash of resource body)
    - Set ``Last-Modified`` header (to the last modification date)
    - Honor the ``If-modified-since`` header (if the resource was not
      modified, return 304)

    Planned features:

    - Return response as a stream, to avoid loading everything in memory.
    - Honor the ``If-Match`` / ``If-None-Match`` headers
    - Support ``Range`` requests + 206 partial response
    - Set ``Cache-control`` and ``Expire`` headers (?)
    - Properly support HEAD requests.

    :param resource_id:
        Id of the resource to be served

    :param transfer_block_size:
        Size of the streaming response size. Defaults to 4096 bytes.

    :return:
        A valid return value for a Flask view.
    """

    with db, db.cursor() as cur:
        query = querybuilder.select_pk("resource", fields="id, mimetype, data_oid, mtime, hash")
        cur.execute(query, dict(id=resource_id))
        resource = cur.fetchone()

    if resource is None:
        raise NotFound()

    mimetype = resource["mimetype"] or "application/octet-stream"
    headers = {
        "Content-type": mimetype,
        "Last-modified": resource["mtime"].strftime(HTTP_DATE_FORMAT),
        "ETag": resource["hash"],
    }

    # ------------------------------------------------------------
    # Check the if-modified-since header

    if "if-modified-since" in request.headers:
        try:
            if_modified_since_date = datetime.strptime(request.headers["if-modified-since"], HTTP_DATE_FORMAT)
        except:
            raise BadRequest("Invalid If-Modified-Since header value")

        if if_modified_since_date >= resource["mtime"]:
            # The resource was not modified -> return ``304 NOT MODIFIED``
            return Response("", status=304, headers=headers)

    # ------------------------------------------------------------
    # Stream the response data

    with db:
        lobject = db.lobject(oid=resource["data_oid"], mode="rb")
        data = lobject.read()
        lobject.close()

    return Response(data, status=200, headers=headers)
Ejemplo n.º 9
0
def serve_resource(resource_id, transfer_block_size=4096):
    """
    Serve resource data via HTTP, setting ETag and Last-Modified headers
    and honoring ``If-None-Match`` and ``If-modified-since`` headers.

    Currently supported features:

    - Set ``ETag`` header (to the hash of resource body)
    - Set ``Last-Modified`` header (to the last modification date)
    - Honor the ``If-modified-since`` header (if the resource was not
      modified, return 304)

    Planned features:

    - Return response as a stream, to avoid loading everything in memory.
    - Honor the ``If-Match`` / ``If-None-Match`` headers
    - Support ``Range`` requests + 206 partial response
    - Set ``Cache-control`` and ``Expire`` headers (?)
    - Properly support HEAD requests.

    :param resource_id:
        Id of the resource to be served

    :param transfer_block_size:
        Size of the streaming response size. Defaults to 4096 bytes.

    :return:
        A valid return value for a Flask view.
    """

    with db, db.cursor() as cur:
        query = querybuilder.select_pk(
            'resource', fields='id, mimetype, data_oid, mtime, hash')
        cur.execute(query, dict(id=resource_id))
        resource = cur.fetchone()

    if resource is None:
        raise NotFound()

    mimetype = resource['mimetype'] or 'application/octet-stream'
    headers = {
        'Content-type': mimetype,
        'Last-modified': resource['mtime'].strftime(HTTP_DATE_FORMAT),
        'ETag': resource['hash'],
    }

    # ------------------------------------------------------------
    # Check the if-modified-since header

    if 'if-modified-since' in request.headers:
        try:
            if_modified_since_date = datetime.strptime(
                request.headers['if-modified-since'], HTTP_DATE_FORMAT)
        except:
            raise BadRequest("Invalid If-Modified-Since header value")

        if if_modified_since_date >= resource['mtime']:
            # The resource was not modified -> return ``304 NOT MODIFIED``
            return Response('', status=304, headers=headers)

    # ------------------------------------------------------------
    # Stream the response data

    with db:
        lobject = db.lobject(oid=resource['data_oid'], mode='rb')
        data = lobject.read()
        lobject.close()

    return Response(data, status=200, headers=headers)
 def open_resource(self):
     oid = self._resource_record['data_oid']
     return db.lobject(oid=oid, mode='rb')
 def open_resource(self):
     oid = self._resource_record['data_oid']
     return db.lobject(oid=oid, mode='rb')