Code Monkey home page Code Monkey logo

cantina's Introduction

cantina

Stupid web application that checks if the next meal's food at the University of Aveiro's canteens is good.

https://fabiomaia.github.io/cantina/

cantina

Problem

Cross-domain AJAX requests are forbidden in the browser by the same-origin security policy. The API made available by the university does not allow cross-origin requests via CORS, so I can't just directly hit the API from the browser. Furthermore, since the university's API is served over HTTP, serving this application over HTTPS would throw mixed-content errors in most modern browsers.

Solutions

CORS

One solution is to run a proxy server-side that hits the API for me and serve it over HTTPS on an endpoint that accepts CORS requests. However, this requires a budget for server bills as well as maintenance upkeep to ensure the proxy is still running, which I am not willing to provide for such a stupid application.

There are CORS proxies available as a service that will proxy our request and serve it over HTTPS and CORS for free. In practice this means that instead of requesting

http://services.web.ua.pt/sas/ementas?date=day&format=json

we can instead simply request

https://cors.io/?http://services.web.ua.pt/sas/ementas?date=day&format=json

CORS is the modern and recommended solution for running cross-origin requests.

JSONP

Alternatively JSONP is an older technique that precedes CORS that is useful in rare scenarios where you need to support old browsers and only need to mimic read-only GET requests (not POST or PUT which it inherently cannot do).

Fundamentally it takes advantage of the fact that you can always embed arbitrary cross-domain scripts in a page, e.g.

<script src="http://services.web.ua.pt/sas/ementas?date=day&format=jsonp&cb=updateAnswer"></script>

If instead of a typical JSON-encoded HTTP response like

{"@attributes":{"request":"\/sas\/ementas","request_timestamp":"1564579826"},"menus":{"@attributes":{"zone":"santiago","type":"day"},"menu":[{"@attributes":{"canteen":"Refeit\u00f3rio de Santiago","meal":"Almo\u00e7o","date":"Wed, 31 Jul 2019 14:30:01 +0100","weekday":"Wednesday","weekdayNr":"3","disabled":"Encerrado - refei\u00e7\u00f5es servidas no refeit\u00f3rio do crasto"},"items":{}},{"@attributes":{"canteen":"Refeit\u00f3rio de Santiago","meal":"Jantar","date":"Wed, 31 Jul 2019 14:30:01 +0100","weekday":"Wednesday","weekdayNr":"3","disabled":"Encerrado - refei\u00e7\u00f5es servidas no refeit\u00f3rio do crasto"},"items":{}},{"@attributes":{"canteen":"Refeit\u00f3rio do Crasto","meal":"Almo\u00e7o","date":"Wed, 31 Jul 2019 14:30:01 +0100","weekday":"Wednesday","weekdayNr":"3","disabled":"0"},"items":{"item":["Sopa de nabi\u00e7as","Bife de peru grelhado e batata cozida","Arroz de marisco","Cozido simples","Badejo cozido com batata cozida e feij\u00e3o verde","Fruta da \u00e9poca ou doce","Buffet de saladas",{"@attributes":{"name":"Diversos"}},"P\u00e3o de mistura"]}},{"@attributes":{"canteen":"Refeit\u00f3rio do Crasto","meal":"Jantar","date":"Wed, 31 Jul 2019 14:30:01 +0100","weekday":"Wednesday","weekdayNr":"3","disabled":"0"},"items":{"item":["Sopa de nabi\u00e7as","Frango estufado com arroz de ervilhas",{"@attributes":{"name":"Prato normal peixe"}},"Seitan de cebolada",{"@attributes":{"name":"Prato vegetariano"}},{"@attributes":{"name":"Prato op\u00e7\u00e3o"}},"Buffet de saladas","P\u00e3o de mistura","Fruta da \u00e9poca ou doce"]}},{"@attributes":{"canteen":"Snack-Bar\/Self","meal":"Almo\u00e7o","date":"Wed, 31 Jul 2019 14:30:01 +0100","weekday":"Wednesday","weekdayNr":"3","disabled":"0"},"items":{"item":["Sopa de nabi\u00e7as","Arroz de aves","Espadarte grelhado com molho de mostarda e batata cozida","Buffet de saladas","Cozido simples","Fruta da \u00e9poca ou doce",{"@attributes":{"name":"Bebida"}}]}}]}})

the remote server instead wraps up the HTTP response in a callback function updateAnswer (presumably defined before the embedded script is run) such that it forms valid JavaScript code

updateAnswer({"@attributes":{"request":"\/sas\/ementas","request_timestamp":"1564579826"},"menus":{"@attributes":{"zone":"santiago","type":"day"},"menu":[{"@attributes":{"canteen":"Refeit\u00f3rio de Santiago","meal":"Almo\u00e7o","date":"Wed, 31 Jul 2019 14:30:01 +0100","weekday":"Wednesday","weekdayNr":"3","disabled":"Encerrado - refei\u00e7\u00f5es servidas no refeit\u00f3rio do crasto"},"items":{}},{"@attributes":{"canteen":"Refeit\u00f3rio de Santiago","meal":"Jantar","date":"Wed, 31 Jul 2019 14:30:01 +0100","weekday":"Wednesday","weekdayNr":"3","disabled":"Encerrado - refei\u00e7\u00f5es servidas no refeit\u00f3rio do crasto"},"items":{}},{"@attributes":{"canteen":"Refeit\u00f3rio do Crasto","meal":"Almo\u00e7o","date":"Wed, 31 Jul 2019 14:30:01 +0100","weekday":"Wednesday","weekdayNr":"3","disabled":"0"},"items":{"item":["Sopa de nabi\u00e7as","Bife de peru grelhado e batata cozida","Arroz de marisco","Cozido simples","Badejo cozido com batata cozida e feij\u00e3o verde","Fruta da \u00e9poca ou doce","Buffet de saladas",{"@attributes":{"name":"Diversos"}},"P\u00e3o de mistura"]}},{"@attributes":{"canteen":"Refeit\u00f3rio do Crasto","meal":"Jantar","date":"Wed, 31 Jul 2019 14:30:01 +0100","weekday":"Wednesday","weekdayNr":"3","disabled":"0"},"items":{"item":["Sopa de nabi\u00e7as","Frango estufado com arroz de ervilhas",{"@attributes":{"name":"Prato normal peixe"}},"Seitan de cebolada",{"@attributes":{"name":"Prato vegetariano"}},{"@attributes":{"name":"Prato op\u00e7\u00e3o"}},"Buffet de saladas","P\u00e3o de mistura","Fruta da \u00e9poca ou doce"]}},{"@attributes":{"canteen":"Snack-Bar\/Self","meal":"Almo\u00e7o","date":"Wed, 31 Jul 2019 14:30:01 +0100","weekday":"Wednesday","weekdayNr":"3","disabled":"0"},"items":{"item":["Sopa de nabi\u00e7as","Arroz de aves","Espadarte grelhado com molho de mostarda e batata cozida","Buffet de saladas","Cozido simples","Fruta da \u00e9poca ou doce",{"@attributes":{"name":"Bebida"}}]}}]}})

then one can embed this script and trigger the updateAnswer function call (with the data that we wanted to obtain) which can finally process the data arbitrarily. In essence this is equivalent to requesting the resource as originally intended, and is effectively circumnavigating the same-origin security policy.

Programatically,

function updateAnswer(json) {
    // ...
}

function getJSONP(url, param, cb) {
    const script = document.createElement('script')
    script.src = `${url}&${param}=${cb.name}`
    document.querySelector('head').appendChild(script)
}

getJSONP('http://services.web.ua.pt/sas/ementas?date=day&format=jsonp&cb=updateAnswer', 'cb', updateAnswer)

Embedded scripts are likely to be cached by the browser though. You may want to force a fresh request each time by appending something unique to the query string (e.g. the current Unix timestamp) to invalidate the cache.

function getJSONP(url, param, cb) {
    const script = document.createElement('script')
    script.src = `${url}&${param}=${cb.name}&v=${Date.now()}`
    document.querySelector('head').appendChild(script)
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.