Skip to content

Commit a8e2470

Browse files
diningPhilosopher64Prabhakar Kumar
authored andcommitted
Fixes a bug that prevent the uploading of large files into MATLAB.
fixes #7
1 parent a4e729e commit a8e2470

File tree

2 files changed

+76
-47
lines changed

2 files changed

+76
-47
lines changed

matlab_proxy/app.py

Lines changed: 75 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,19 @@
77
import sys
88

99
import aiohttp
10-
from aiohttp import web
10+
from aiohttp import client_exceptions, web
1111
from aiohttp_session import setup as aiohttp_session_setup
1212
from aiohttp_session.cookie_storage import EncryptedCookieStorage
1313
from cryptography import fernet
1414

1515
import matlab_proxy
16-
from matlab_proxy import settings, util
16+
from matlab_proxy import constants, settings, util
1717
from matlab_proxy.app_state import AppState
1818
from matlab_proxy.default_configuration import config
1919
from matlab_proxy.util import list_servers, mwi
2020
from matlab_proxy.util.mwi import environment_variables as mwi_env
2121
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
2723

2824
mimetypes.add_type("font/woff", ".woff")
2925
mimetypes.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(

matlab_proxy/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
"""This module defines project-level constants"""
44
CONNECTOR_SECUREPORT_FILENAME = "connector.securePort"
55
VERSION_INFO_FILE_NAME = "VersionInfo.xml"
6+
MAX_HTTP_REQUEST_SIZE = 500_000_000 # 500MB

0 commit comments

Comments
 (0)