2828 json_writer ,
2929 xml_writer ,
3030)
31+ # (canada fork only): filename to save stream to
32+ import re
33+
34+
35+ # (canada fork only): filename to save stream to
36+ FILENAME_MATCH = re .compile ('^[\w\-\.]+$' )
3137
3238int_validator = get_validator (u'int_validator' )
3339boolean_validator = get_validator (u'boolean_validator' )
@@ -75,6 +81,18 @@ def exclude_id_from_ds_dump(key, data, errors, context):
7581 data [key ] = value
7682
7783
84+ # (canada fork only): filename to save stream to
85+ def filename_safe (key , data , errors , context ):
86+ """
87+ Makes sure the passed filename is safe to stream back in the response.
88+ """
89+ value = data .get (key )
90+
91+ if not re .search (FILENAME_MATCH , value ):
92+ errors [key ].append (_ ('Invalid characters in filename' ))
93+ raise StopOnError
94+
95+
7896def dump_schema () -> Schema :
7997 return {
8098 u'offset' : [default (0 ), int_validator ],
@@ -88,6 +106,7 @@ def dump_schema() -> Schema:
88106 u'language' : [ignore_missing , unicode_only ],
89107 u'fields' : [exclude_id_from_ds_dump , ignore_missing , list_of_strings_or_string ], # (canada fork only): exclude _id field from Blueprint dump
90108 u'sort' : [default (u'_id' ), list_of_strings_or_string ],
109+ 'filename' : [ignore_missing , unicode_only , filename_safe ] # (canada fork only): filename to save stream to
91110 }
92111
93112
@@ -111,6 +130,8 @@ def dump(resource_id: str):
111130 limit = data .get ('limit' )
112131 options = {'bom' : data ['bom' ]}
113132 sort = data ['sort' ]
133+ # (canada fork only): filename to save stream to
134+ filename = data .get ('filename' , resource_id )
114135 search_params = {
115136 k : v
116137 for k , v in data .items ()
@@ -127,19 +148,19 @@ def dump(resource_id: str):
127148
128149 if fmt == 'csv' :
129150 content_disposition = 'attachment; filename="{name}.csv"' .format (
130- name = resource_id )
151+ name = filename ) # (canada fork only): filename to save stream to
131152 content_type = b'text/csv; charset=utf-8'
132153 elif fmt == 'tsv' :
133154 content_disposition = 'attachment; filename="{name}.tsv"' .format (
134- name = resource_id )
155+ name = filename ) # (canada fork only): filename to save stream to
135156 content_type = b'text/tab-separated-values; charset=utf-8'
136157 elif fmt == 'json' :
137158 content_disposition = 'attachment; filename="{name}.json"' .format (
138- name = resource_id )
159+ name = filename ) # (canada fork only): filename to save stream to
139160 content_type = b'application/json; charset=utf-8'
140161 elif fmt == 'xml' :
141162 content_disposition = 'attachment; filename="{name}.xml"' .format (
142- name = resource_id )
163+ name = filename ) # (canada fork only): filename to save stream to
143164 content_type = b'text/xml; charset=utf-8'
144165 else :
145166 abort (404 , _ ('Unsupported format' ))
0 commit comments