Orion Poplawski 65d4a76
diff -ur ipython-2.4.1/IPython/html/base/handlers.py ipython/IPython/html/base/handlers.py
Orion Poplawski 65d4a76
--- ipython-2.4.1/IPython/html/base/handlers.py	2015-02-09 15:59:57.000000000 -0700
Orion Poplawski 65d4a76
+++ ipython/IPython/html/base/handlers.py	2015-07-16 09:08:21.874322394 -0600
Orion Poplawski 65d4a76
@@ -29,6 +29,10 @@
Orion Poplawski 65d4a76
     from http.client import responses
Orion Poplawski 65d4a76
 except ImportError:
Orion Poplawski 65d4a76
     from httplib import responses
Orion Poplawski 65d4a76
+try:
Orion Poplawski 65d4a76
+    from urllib.parse import urlparse # Py 3
Orion Poplawski 65d4a76
+except ImportError:
Orion Poplawski 65d4a76
+    from urlparse import urlparse # Py 2
Orion Poplawski 65d4a76
 
Orion Poplawski 65d4a76
 from jinja2 import TemplateNotFound
Orion Poplawski 65d4a76
 from tornado import web
Orion Poplawski 65d4a76
@@ -208,6 +212,50 @@
Orion Poplawski 65d4a76
             origin = self.request.headers.get("Sec-Websocket-Origin", None)
Orion Poplawski 65d4a76
         return origin
Orion Poplawski 65d4a76
 
Orion Poplawski 65d4a76
+    def check_origin_api(self):
Orion Poplawski 65d4a76
+        """Check Origin for cross-site API requests.
Orion Poplawski 65d4a76
+        
Orion Poplawski 65d4a76
+        Copied from WebSocket with changes:
Orion Poplawski 65d4a76
+        
Orion Poplawski 65d4a76
+        - allow unspecified host/origin (e.g. scripts)
Orion Poplawski 65d4a76
+        """
Orion Poplawski 65d4a76
+        if self.allow_origin == '*':
Orion Poplawski 65d4a76
+            return True
Orion Poplawski 65d4a76
+
Orion Poplawski 65d4a76
+        host = self.request.headers.get("Host")
Orion Poplawski 65d4a76
+        origin = self.request.headers.get("Origin")
Orion Poplawski 65d4a76
+
Orion Poplawski 65d4a76
+        # If no header is provided, assume it comes from a script/curl.
Orion Poplawski 65d4a76
+        # We are only concerned with cross-site browser stuff here.
Orion Poplawski 65d4a76
+        if origin is None or host is None:
Orion Poplawski 65d4a76
+            return True
Orion Poplawski 65d4a76
+        
Orion Poplawski 65d4a76
+        origin = origin.lower()
Orion Poplawski 65d4a76
+        origin_host = urlparse(origin).netloc
Orion Poplawski 65d4a76
+        
Orion Poplawski 65d4a76
+        # OK if origin matches host
Orion Poplawski 65d4a76
+        if origin_host == host:
Orion Poplawski 65d4a76
+            return True
Orion Poplawski 65d4a76
+        
Orion Poplawski 65d4a76
+        # Check CORS headers
Orion Poplawski 65d4a76
+        if self.allow_origin:
Orion Poplawski 65d4a76
+            allow = self.allow_origin == origin
Orion Poplawski 65d4a76
+        elif self.allow_origin_pat:
Orion Poplawski 65d4a76
+            allow = bool(self.allow_origin_pat.match(origin))
Orion Poplawski 65d4a76
+        else:
Orion Poplawski 65d4a76
+            # No CORS headers deny the request
Orion Poplawski 65d4a76
+            allow = False
Orion Poplawski 65d4a76
+        if not allow:
Orion Poplawski 65d4a76
+            self.log.warn("Blocking Cross Origin API request.  Origin: %s, Host: %s",
Orion Poplawski 65d4a76
+                origin, host,
Orion Poplawski 65d4a76
+            )
Orion Poplawski 65d4a76
+        return allow
Orion Poplawski 65d4a76
+
Orion Poplawski 65d4a76
+    def prepare(self):
Orion Poplawski 65d4a76
+        if not self.check_origin_api():
Orion Poplawski 65d4a76
+            raise web.HTTPError(404)
Orion Poplawski 65d4a76
+        return super(IPythonHandler, self).prepare()
Orion Poplawski 65d4a76
+
Orion Poplawski 65d4a76
     #---------------------------------------------------------------
Orion Poplawski 65d4a76
     # template rendering
Orion Poplawski 65d4a76
     #---------------------------------------------------------------
Orion Poplawski 65d4a76
@@ -339,6 +387,7 @@
Orion Poplawski 65d4a76
             message = e.log_message
Orion Poplawski 65d4a76
             self.log.warn(message)
Orion Poplawski 65d4a76
             self.set_status(e.status_code)
Orion Poplawski 65d4a76
+            self.set_header('Content-Type', 'application/json')
Orion Poplawski 65d4a76
             self.finish(json.dumps(dict(message=message)))
Orion Poplawski 65d4a76
         except Exception:
Orion Poplawski 65d4a76
             self.log.error("Unhandled error in API request", exc_info=True)
Orion Poplawski 65d4a76
@@ -348,6 +397,7 @@
Orion Poplawski 65d4a76
             self.set_status(status)
Orion Poplawski 65d4a76
             tb_text = ''.join(traceback.format_exception(t, value, tb))
Orion Poplawski 65d4a76
             reply = dict(message=message, traceback=tb_text)
Orion Poplawski 65d4a76
+            self.set_header('Content-Type', 'application/json')
Orion Poplawski 65d4a76
             self.finish(json.dumps(reply))
Orion Poplawski 65d4a76
         else:
Orion Poplawski 65d4a76
             return result