That endpoint was wired to a function in the related Controller … and when that upload came in it obviously had no idea who was uploading the file or what the context was, so it had to lookup the resource that the upload was supposed to be related to, check the user authentication, and then make sure that based on the authentication that that gave the uploader the rights to access that resource. Also, since different users in the system have different upload limits, it had to check and enforce that as well.
Anyone with a network connection could hit that endpoint with a file. Think about that: it means that anyone could consume bandwidth and be sending rando file data to the server. So, that upload endpoint had to be very careful about the auth, needed rate-limiting (but not in a way to annoy allowed users!), needed to allow fairly large files through even though that data may end up being entirely discarded as later authorization based on the data may fail. And it had to do that on every request … and again, anyone on the internet could initiate a file upload to that website. Not … great.
Some of the logic for upload size was in Endpoint configuration, some in a wrapper for the Multipart upload plug, and some in the Controller. Ugh.
Enter LiveView uploads … when the LiveView page is loaded, authorization occurs and the stateful websocket connection enters a ‘trusted’ state: the app has confirmed who is on the other end of that connection. Even better, it looks up that user account’s rights: can they upload to this item? (Some users can access, or even edit, but not upload!) What is their file upload allowance? etc. It does this once on websocket setup (the “mount” in LiveView). Based on that information, it then
allow_upload/3's all the uploads along with details like max upload size … it can ever vary things like timeouts and data chunk sizes (not that I do in this case).
It does this once. And only after authorization (implying authentication) has occurred. Nobody can get at the file upload code, at all, in that app until they have authenticated. There is no public endpoint for it anymore. Instead, it is a function on the server-side that accepts data (or not!) over the stateful websocket connection.
It’s more efficient (one time per page, no matter how many uploads, and a smaller page size due to dropping that JS lib and it’s CSS), less things to get wrong (it isn’t spread out everywhere), and has a significantly smaller security surface.