77import sys
88
99import aiohttp
10- from aiohttp import web
10+ from aiohttp import client_exceptions , web
1111from aiohttp_session import setup as aiohttp_session_setup
1212from aiohttp_session .cookie_storage import EncryptedCookieStorage
1313from cryptography import fernet
1414
1515import matlab_proxy
16- from matlab_proxy import settings , util
16+ from matlab_proxy import constants , settings , util
1717from matlab_proxy .app_state import AppState
1818from matlab_proxy .default_configuration import config
1919from matlab_proxy .util import list_servers , mwi
2020from matlab_proxy .util .mwi import environment_variables as mwi_env
2121from 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
2723
2824mimetypes .add_type ("font/woff" , ".woff" )
2925mimetypes .add_type ("font/woff2" , ".woff2" )
@@ -465,46 +461,63 @@ async def matlab_view(req):
465461 async with aiohttp .ClientSession (
466462 cookies = req .cookies , connector = aiohttp .TCPConnector (verify_ssl = False )
467463 ) 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 } "
505513 )
506514
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 )
508521
509522 # Standard HTTP Request
510523 else :
@@ -530,7 +543,22 @@ async def wsforward(ws_from, ws_to):
530543 headers .update (req .app ["settings" ]["mwi_custom_http_headers" ])
531544
532545 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+ )
534562 raise web .HTTPNotFound ()
535563
536564
@@ -683,7 +711,7 @@ def create_app(config_name=matlab_proxy.get_default_config_name()):
683711 Returns:
684712 aiohttp server: An aiohttp server with routes, settings and env_config.
685713 """
686- app = web .Application ()
714+ app = web .Application (client_max_size = constants . MAX_HTTP_REQUEST_SIZE )
687715
688716 # Get application settings
689717 app ["settings" ] = settings .get (
0 commit comments