7
7
import sys
8
8
9
9
import aiohttp
10
- from aiohttp import web
10
+ from aiohttp import client_exceptions , web
11
11
from aiohttp_session import setup as aiohttp_session_setup
12
12
from aiohttp_session .cookie_storage import EncryptedCookieStorage
13
13
from cryptography import fernet
14
14
15
15
import matlab_proxy
16
- from matlab_proxy import settings , util
16
+ from matlab_proxy import constants , settings , util
17
17
from matlab_proxy .app_state import AppState
18
18
from matlab_proxy .default_configuration import config
19
19
from matlab_proxy .util import list_servers , mwi
20
20
from matlab_proxy .util .mwi import environment_variables as mwi_env
21
21
from matlab_proxy .util .mwi import token_auth
22
- from matlab_proxy .util .mwi .exceptions import (
23
- AppError ,
24
- InvalidTokenError ,
25
- LicensingError ,
26
- )
22
+ from matlab_proxy .util .mwi .exceptions import AppError , InvalidTokenError , LicensingError
27
23
28
24
mimetypes .add_type ("font/woff" , ".woff" )
29
25
mimetypes .add_type ("font/woff2" , ".woff2" )
@@ -465,46 +461,63 @@ async def matlab_view(req):
465
461
async with aiohttp .ClientSession (
466
462
cookies = req .cookies , connector = aiohttp .TCPConnector (verify_ssl = False )
467
463
) as client_session :
468
- async with client_session .ws_connect (
469
- matlab_base_url + req .path_qs ,
470
- ) as ws_client :
471
-
472
- async def wsforward (ws_from , ws_to ):
473
- async for msg in ws_from :
474
- mt = msg .type
475
- md = msg .data
476
-
477
- # When a websocket is closed by the MATLAB JSD, it sends out a few http requests to the Embedded Connector about the events
478
- # that had occured (figureWindowClosed etc.)
479
- # The Embedded Connector responds by sending a message of type 'Error' with close code as Abnormal closure.
480
- # When this happens, matlab-proxy can safely exit out of the loop
481
- # and close the websocket connection it has with the Embedded Connector (ws_client)
482
- if (
483
- mt == aiohttp .WSMsgType .ERROR
484
- and ws_from .close_code
485
- == aiohttp .WSCloseCode .ABNORMAL_CLOSURE
486
- ):
487
- break
488
-
489
- if mt == aiohttp .WSMsgType .TEXT :
490
- await ws_to .send_str (md )
491
- elif mt == aiohttp .WSMsgType .BINARY :
492
- await ws_to .send_bytes (md )
493
- elif mt == aiohttp .WSMsgType .PING :
494
- await ws_to .ping ()
495
- elif mt == aiohttp .WSMsgType .PONG :
496
- await ws_to .pong ()
497
- elif ws_to .closed :
498
- await ws_to .close (code = ws_to .close_code , message = msg .extra )
499
- else :
500
- raise ValueError (f"Unexpected message type: { msg } " )
501
-
502
- await asyncio .wait (
503
- [wsforward (ws_server , ws_client ), wsforward (ws_client , ws_server )],
504
- return_when = asyncio .FIRST_COMPLETED ,
464
+ try :
465
+ async with client_session .ws_connect (
466
+ matlab_base_url + req .path_qs ,
467
+ ) as ws_client :
468
+
469
+ async def wsforward (ws_from , ws_to ):
470
+ async for msg in ws_from :
471
+ mt = msg .type
472
+ md = msg .data
473
+
474
+ # When a websocket is closed by the MATLAB JSD, it sends out a few http requests to the Embedded Connector about the events
475
+ # that had occured (figureWindowClosed etc.)
476
+ # The Embedded Connector responds by sending a message of type 'Error' with close code as Abnormal closure.
477
+ # When this happens, matlab-proxy can safely exit out of the loop
478
+ # and close the websocket connection it has with the Embedded Connector (ws_client)
479
+ if (
480
+ mt == aiohttp .WSMsgType .ERROR
481
+ and ws_from .close_code
482
+ == aiohttp .WSCloseCode .ABNORMAL_CLOSURE
483
+ ):
484
+ break
485
+
486
+ if mt == aiohttp .WSMsgType .TEXT :
487
+ await ws_to .send_str (md )
488
+ elif mt == aiohttp .WSMsgType .BINARY :
489
+ await ws_to .send_bytes (md )
490
+ elif mt == aiohttp .WSMsgType .PING :
491
+ await ws_to .ping ()
492
+ elif mt == aiohttp .WSMsgType .PONG :
493
+ await ws_to .pong ()
494
+ elif ws_to .closed :
495
+ await ws_to .close (
496
+ code = ws_to .close_code , message = msg .extra
497
+ )
498
+ else :
499
+ raise ValueError (f"Unexpected message type: { msg } " )
500
+
501
+ await asyncio .wait (
502
+ [
503
+ wsforward (ws_server , ws_client ),
504
+ wsforward (ws_client , ws_server ),
505
+ ],
506
+ return_when = asyncio .FIRST_COMPLETED ,
507
+ )
508
+ return ws_server
509
+
510
+ except Exception as err :
511
+ logger .error (
512
+ f"Failed to create web socket connection with error: { err } "
505
513
)
506
514
507
- return ws_server
515
+ code , message = (
516
+ aiohttp .WSCloseCode .INTERNAL_ERROR ,
517
+ "Failed to establish websocket connection with MATLAB" ,
518
+ )
519
+ await ws_server .close (code = code , message = message .encode ("utf-8" ))
520
+ raise aiohttp .WebSocketError (code = code , message = message )
508
521
509
522
# Standard HTTP Request
510
523
else :
@@ -530,7 +543,22 @@ async def wsforward(ws_from, ws_to):
530
543
headers .update (req .app ["settings" ]["mwi_custom_http_headers" ])
531
544
532
545
return web .Response (headers = headers , status = res .status , body = body )
533
- except Exception :
546
+
547
+ # Handles any pending HTTP requests from the browser when the MATLAB process is terminated before responding to them.
548
+ except (
549
+ client_exceptions .ServerDisconnectedError ,
550
+ client_exceptions .ClientConnectionError ,
551
+ ):
552
+ logger .debug (
553
+ "Failed to forward HTTP request as MATLAB process may not be running."
554
+ )
555
+ raise web .HTTPServiceUnavailable ()
556
+
557
+ # Some other exception has been raised (by MATLAB Embedded Connector), log the error and return 404
558
+ except Exception as err :
559
+ logger .error (
560
+ f"Failed to forward HTTP request to MATLAB with error: { err } "
561
+ )
534
562
raise web .HTTPNotFound ()
535
563
536
564
@@ -683,7 +711,7 @@ def create_app(config_name=matlab_proxy.get_default_config_name()):
683
711
Returns:
684
712
aiohttp server: An aiohttp server with routes, settings and env_config.
685
713
"""
686
- app = web .Application ()
714
+ app = web .Application (client_max_size = constants . MAX_HTTP_REQUEST_SIZE )
687
715
688
716
# Get application settings
689
717
app ["settings" ] = settings .get (
0 commit comments