Λήψη Αρχείων (/file)
Λήψη Αρχείων
Το endpoint /file σερβίρει δυαδικά αρχεία που παράγονται από μια συνάρτηση PostgreSQL — χωρίς base64 μέσα
στο JSON-RPC. Ένα επιστρεφόμενο αρχείο αποστέλλεται ως έχει· πολλά αρχεία πακετάρονται σε αρχείο ZIP εν κινήσει.
POST /{prefix}/{database}/fileΗ πιστοποίηση, η εναλλαγή ρόλου (SET LOCAL ROLE), το rate limiting και το όριο μεγέθους του request
είναι ίδια με το /jsonrpc. Ο καλών χρειάζεται EXECUTE στη συνάρτηση.
Request
{
"method": "api.export_documents",
"params": { "count": 3 },
"options": { "filename": "export.zip", "force_zip": false, "compression_level": 6 },
"idempotencyKey": "optional"
}| Πεδίο | Περιγραφή |
|---|---|
method | Υποχρεωτικό. schema.function, καλείται ως fn(params::jsonb). |
params | Περνά στη συνάρτηση ως jsonb (προεπιλογή {}). |
options.filename | Όνομα του αρχείου/ZIP που λαμβάνεται. Προεπιλογή: το ίδιο το όνομα του αρχείου ή export-YYYYMMDD-HHMMSS.zip. |
options.force_zip | Επιστρέφει πάντα ZIP, ακόμη και για ένα αρχείο. |
options.compression_level | 0 = μόνο αποθήκευση, 1–9· προεπιλογή 6. |
Συμβόλαιο βάσης δεδομένων
Η συνάρτηση δέχεται ένα όρισμα jsonb και επιστρέφει ένα σύνολο γραμμών. Τα path και
content είναι υποχρεωτικά· τα mime_type και store_only είναι προαιρετικά.
CREATE FUNCTION api.export_documents(params jsonb)
RETURNS TABLE (path text, content bytea, mime_type text, store_only boolean)
LANGUAGE sql AS $$
SELECT 'report.csv', convert_to('a,b' || E'\n' || '1,2', 'UTF8'), 'text/csv', false;
$$;- Το
pathπρέπει να είναι απλή σχετική διαδρομή, ασφαλής για εξαγωγή σε κάθε λειτουργικό σύστημα. Μια διαδρομή απορρίπτεται (το request αποτυγχάνει με 500 και το πρόβλημα καταγράφεται στο log) αν:- είναι κενή, μεγαλύτερη από 512 bytes, δεν είναι έγκυρο UTF-8 ή περιέχει χαρακτήρες ελέγχου·
- είναι απόλυτη (
/…,C:…) ή περιέχει backslash· - έχει κενό τμήμα ή τμήμα
.ή..· - έχει τμήμα που τελειώνει με τελεία ή κενό (τα Windows τα αφαιρούν, οπότε το
".. "θα γινόταν..)· - περιέχει
:(εναλλακτική ροή δεδομένων NTFS) ή οποιονδήποτε από τους χαρακτήρες< > " | ? *· - χρησιμοποιεί ως τμήμα δεσμευμένο όνομα συσκευής των Windows, με ή χωρίς επέκταση (
CON,PRN,AUX,NUL,COM0–COM9,LPT0–LPT9)· - συγκρούεται με άλλη διαδρομή στην ίδια απάντηση: τα ονόματα συγκρίνονται χωρίς διάκριση πεζών-κεφαλαίων (τα
a.txtκαιA.TXTσυγκρούονται σε macOS/Windows) και ένα αρχείο δεν μπορεί να είναι ταυτόχρονα και φάκελος (aκαιa/b).
- Το
contentμε τιμήNULLσημαίνει κενό αρχείο. - Το
mime_typeχρησιμοποιείται μόνο αν είναι έγκυρος τύπος μέσου, αλλιώς προκύπτει από την επέκταση (εφεδρικάapplication/octet-stream). - Το
store_only = trueαποθηκεύει την εγγραφή ZIP χωρίς συμπίεση (απαιτείται π.χ. για το αρχείοmimetypeτου EPUB).
Απάντηση
| Γραμμές | force_zip | Αποτέλεσμα |
|---|---|---|
| 0 | οποιοδήποτε | 404 (σφάλμα JSON)· η συναλλαγή αναιρείται (rollback), άρα τίποτα από όσα έκανε η συνάρτηση δεν διατηρείται και το idempotencyKey δεν καταναλώνεται |
| 1 | false | το ίδιο το αρχείο, με τον τύπο μέσου του |
| 1 | true | ZIP με μία εγγραφή |
| ≥ 2 | οποιοδήποτε | ZIP (application/zip) |
curl -X POST http://localhost:8080/db/my_database/file \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"method":"api.export_documents","params":{"count":3}}' -OJΤο όνομα λήψης (options.filename ή το όνομα του ίδιου του αρχείου) καθαρίζεται (sanitised): οι διαχωριστές διαδρομής, τα εισαγωγικά και οι δεσμευμένοι χαρακτήρες γίνονται _, ενώ οι χαρακτήρες ελέγχου, παράκαμψης κατεύθυνσης κειμένου, μηδενικού πλάτους και διαχωρισμού γραμμής αφαιρούνται, ώστε ένα όνομα να μη μπορεί να μεταμφιεστεί σε αρχείο άλλου τύπου.
Τα σφάλματα επιστρέφονται πάντα ως JSON, ποτέ ως δυαδικά δεδομένα: 400 μη έγκυρο request, 401 μη πιστοποιημένος,
403 χωρίς δικαίωμα, 404 άγνωστη συνάρτηση ή καθόλου γραμμές, 413 η απάντηση
υπερβαίνει το FILE_MAX_BYTES / FILE_MAX_ENTRIES, 500 η συνάρτηση απέτυχε ή
επέστρεψε μη έγκυρη δομή.
Ασφαλές εκ κατασκευής
Η βάση δεδομένων ελέγχει μόνο ονόματα αρχείων, περιεχόμενα και τύπους μέσων — ποτέ τις κεφαλίδες HTTP. Οι απαντήσεις έχουν πάντα
Content-Disposition: attachment μαζί με X-Content-Type-Options: nosniff,
Content-Security-Policy: sandbox και Cache-Control: no-store, έτσι ώστε μια συνάρτηση
που επιστρέφει text/html ή SVG να μην μπορεί να εκτελέσει script στο origin του API. Τα ονόματα αρχείων καθαρίζονται (sanitised).
Ολόκληρο το αποτέλεσμα αποθηκεύεται προσωρινά στη μνήμη: το πραγματικό όριο ανά request είναι το FILE_MAX_BYTES συν η μεγαλύτερη μεμονωμένη γραμμή, επειδή ο driver της βάσης διαβάζει μια γραμμή ολόκληρη πριν ελεγχθεί το όριο — λάβετε υπόψη τον αριθμό των ταυτόχρονων λήψεων. Το ίδιο το ZIP αποστέλλεται σε ροή.
Ανακάλυψη
Μια συνάρτηση που επιστρέφει σύνολο γραμμών, δηλωμένη με RETURNS TABLE (…) ή παραμέτρους OUT που περιλαμβάνουν στήλες path και content, αναφέρεται από το
capabilities με "kind": "file" και endpoint /file. Η προδιαγραφή OpenAPI
τεκμηριώνει μια πραγματική λειτουργία POST /{prefix}/{database}/file (μόνο για ρόλους που μπορούν να εκτελέσουν
συνάρτηση αρχείου)· οι συναρτήσεις αρχείων δεν εκτίθενται ως εργαλεία MCP.