Kirill Simonov avatar Kirill Simonov committed acfa16f

Added `Content-Disposition` header to `:json` and `:csv` renderers.

Comments (0)

Files changed (4)

src/htsql/fmt/json.py

         return "200 OK"
 
     def generate_headers(self, product):
-        return [('Content-Type', 'application/json')]
+        filename = str(product.profile.segment.syntax)
+        filename = filename.replace('\\', '\\\\').replace('"', '\\"')
+        return [('Content-Type', 'application/json'),
+                ('Content-Disposition',
+                 'attachment; filename="(%s).json"' % filename)]
 
     def generate_body(self, product):
         if not product:

src/htsql/fmt/spreadsheet.py

         return "200 OK"
 
     def generate_headers(self, product):
-        return [('Content-Type', 'text/csv; charset=UTF-8')]
+        filename = str(product.profile.segment.syntax)
+        filename = filename.replace('\\', '\\\\').replace('"', '\\"')
+        return [('Content-Type', 'text/csv; charset=UTF-8'),
+                ('Content-Disposition',
+                 'attachment; filename="(%s).csv"' % filename)]
 
     def generate_body(self, product):
         if not product:

test/input/pgsql.yaml

     - uri: /school/:html
     - uri: /school/:unknown
       expect: 400
+    # Verify that the filename in `Content-Disposition` field
+    # is properly escaped.
+    - uri: /{'%01%02...%1F%7F\"'}
+      headers:
+        Accept: text/csv
 

test/output/pgsql.yaml

       status: 200 OK
       headers:
       - [Content-Type, application/json]
+      - [Content-Disposition, attachment; filename="(school).json"]
       body: |
         [
           ["art", "School of Art and Design"],
       status: 200 OK
       headers:
       - [Content-Type, text/csv; charset=UTF-8]
+      - [Content-Disposition, attachment; filename="(school).csv"]
       body: "code,name\r\nart,School of Art and Design\r\nbus,School of Business\r\nedu,College
         of Education\r\negn,School of Engineering\r\nla,\"School of Arts, Letters,
         and the Humanities\"\r\nmart,School of Modern Art\r\nmus,Musical School\r\nns,School
       status: 200 OK
       headers:
       - [Content-Type, text/csv; charset=UTF-8]
+      - [Content-Disposition, 'attachment; filename="((school as ''School Record''){code
+          as ''Code name'',name as ''Long name''}).csv"']
       body: "Code name,Long name\r\nart,School of Art and Design\r\nbus,School of
         Business\r\nedu,College of Education\r\negn,School of Engineering\r\nla,\"School
         of Arts, Letters, and the Humanities\"\r\nmart,School of Modern Art\r\nmus,Musical
       status: 200 OK
       headers:
       - [Content-Type, application/json]
+      - [Content-Disposition, attachment; filename="(school).json"]
       body: |
         [
           ["art", "School of Art and Design"],
       status: 200 OK
       headers:
       - [Content-Type, text/csv; charset=UTF-8]
+      - [Content-Disposition, attachment; filename="(school).csv"]
       body: "code,name\r\nart,School of Art and Design\r\nbus,School of Business\r\nedu,College
         of Education\r\negn,School of Engineering\r\nla,\"School of Arts, Letters,
         and the Humanities\"\r\nmart,School of Modern Art\r\nmus,Musical School\r\nns,School
         invalid argument: unknown format:
             /school/:unknown
                      ^^^^^^^
+    - uri: /{'%01%02...%1F%7F\"'}
+      status: 200 OK
+      headers:
+      - [Content-Type, text/csv; charset=UTF-8]
+      - [Content-Disposition, 'attachment; filename="({''%01%02...%1F%7F\\\"''}).csv"']
+      body: "\"'%01%02...%1F%7F\\\"\"'\"\r\n\"\x01\x02...\x1F\x7F\\\"\"\"\r\n"
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.