3
3
import tarfile
4
4
import time
5
5
import zipfile
6
+ import threading
6
7
7
8
from jupyter_server .base .handlers import JupyterHandler
8
9
from jupyter_server .utils import url2path , url_path_join
@@ -41,7 +42,8 @@ def write(self, data):
41
42
if time_out_cnt <= 0 :
42
43
raise ValueError ("Time out for writing into tornado buffer" )
43
44
self .position += len (data )
44
- self .handler .write (data )
45
+ with self .handler .lock :
46
+ self .handler .write (data )
45
47
del data
46
48
47
49
def tell (self ):
@@ -89,6 +91,7 @@ def make_reader(archive_path):
89
91
90
92
91
93
class DownloadArchiveHandler (JupyterHandler ):
94
+ lock = threading .Lock ()
92
95
93
96
@property
94
97
def stream_max_buffer_size (self ):
@@ -107,7 +110,8 @@ def flush(self, include_footers=False, force=False):
107
110
stream_buffer = self .request .connection .stream ._write_buffer
108
111
if not force and stream_buffer and len (stream_buffer ) > self .stream_max_buffer_size :
109
112
return
110
- return super (DownloadArchiveHandler , self ).flush (include_footers )
113
+ with self .lock :
114
+ return super (DownloadArchiveHandler , self ).flush (include_footers )
111
115
112
116
@web .authenticated
113
117
async def get (self , archive_path , include_body = False ):
@@ -154,24 +158,28 @@ async def get(self, archive_path, include_body=False):
154
158
self .flush_cb = ioloop .PeriodicCallback (self .flush , self .archive_download_flush_delay )
155
159
self .flush_cb .start ()
156
160
157
- args = (
158
- archive_path ,
159
- archive_format ,
160
- archive_token ,
161
- follow_symlinks ,
162
- download_hidden ,
163
- )
164
- await ioloop .IOLoop .current ().run_in_executor (None , self .archive_and_download , * args )
165
-
166
- if self .canceled :
167
- self .log .info ("Download canceled." )
168
- else :
169
- # Here, we need to flush forcibly to move all data from _write_buffer to stream._write_buffer
170
- self .flush (force = True )
171
- self .log .info ("Finished downloading {}." .format (archive_filename ))
161
+ try :
162
+ args = (
163
+ archive_path ,
164
+ archive_format ,
165
+ archive_token ,
166
+ follow_symlinks ,
167
+ download_hidden ,
168
+ )
169
+ await ioloop .IOLoop .current ().run_in_executor (None , self .archive_and_download , * args )
170
+
171
+ if self .canceled :
172
+ self .log .info ("Download canceled." )
173
+ else :
174
+ # Here, we need to flush forcibly to move all data from _write_buffer to stream._write_buffer
175
+ self .flush (force = True )
176
+ self .log .info ("Finished downloading {}." .format (archive_filename ))
177
+ except Exception :
178
+ raise
179
+ finally :
180
+ self .flush_cb .stop ()
172
181
173
182
self .set_cookie ("archiveToken" , archive_token )
174
- self .flush_cb .stop ()
175
183
self .finish ()
176
184
177
185
def archive_and_download (
0 commit comments