55import re
66
77from modules .timer import startup_timer
8+ from modules import patches
9+ from functools import wraps
810
911
1012def gradio_server_name ():
@@ -191,11 +193,8 @@ def configure_opts_onchange():
191193
192194def setup_middleware (app ):
193195 from starlette .middleware .gzip import GZipMiddleware
194-
195- app .middleware_stack = None # reset current middleware to allow modifying user provided list
196196 app .add_middleware (GZipMiddleware , minimum_size = 1000 )
197197 configure_cors_middleware (app )
198- app .build_middleware_stack () # rebuild middleware stack on-the-fly
199198
200199
201200def configure_cors_middleware (app ):
@@ -213,3 +212,38 @@ def configure_cors_middleware(app):
213212 cors_options ["allow_origin_regex" ] = cmd_opts .cors_allow_origins_regex
214213 app .add_middleware (CORSMiddleware , ** cors_options )
215214
215+
216+ def allow_add_middleware_after_start ():
217+ from starlette .applications import Starlette
218+
219+ def add_middleware_wrapper (func ):
220+ """Patch Starlette.add_middleware to allow for middleware to be added after the app has started
221+
222+ Starlette.add_middleware raises RuntimeError("Cannot add middleware after an application has started") if middleware_stack is not None.
223+ We can force add new middleware by first setting middleware_stack to None, then adding the middleware.
224+ When middleware_stack is None, it will rebuild the middleware_stack on the next request (Lazily build middleware stack).
225+
226+ If packages are updated in the future, things may break, so we have two ways to add middleware after the app has started:
227+ the first way is to just set middleware_stack to None and then retry
228+ the second manually insert the middleware into the user_middleware list without calling add_middleware
229+ """
230+
231+ @wraps (func )
232+ def wrapper (self , * args , ** kwargs ):
233+ res = None
234+ try :
235+ res = func (self , * args , ** kwargs )
236+ except RuntimeError as _ :
237+ try :
238+ self .middleware_stack = None
239+ res = func (self , * args , ** kwargs )
240+ except RuntimeError as e :
241+ print (f'Warning: "{ e } ", Retrying...' )
242+ from starlette .middleware import Middleware
243+ self .user_middleware .insert (0 , Middleware (* args , ** kwargs ))
244+ self .middleware_stack = None # ensure middleware_stack in the event of concurrent requests
245+ return res
246+
247+ return wrapper
248+
249+ patches .patch (__name__ , obj = Starlette , field = "add_middleware" , replacement = add_middleware_wrapper (Starlette .add_middleware ))
0 commit comments