I'm using python with tornado webserver.
the application works fine but I can't find a way to prevent the user on accessing server files directly via url.
for example I have the following files in the server:
program.py
index.html
main.html
i wanted to prevent the user from accessing the above server files directly via web url
ex: localhost:8080/program.py or /index.html
i only wanted them to access localhost:8080/ or /home
Thanks in advance
from ws4py.client.tornadoclient import TornadoWebSocketClient
import tornado.ioloop
import tornado.web
import tornado.websocket
import tornado.template
SETTING_CLIENT_LISTEN_PORT = 8080
class MainHandler(tornado.web.RequestHandler):
def get(self):
try:
loader = tornado.template.Loader(".")
self.write(loader.load("index.html").generate())
except Exception as e:
print("exception occured", e)
class CWSHandler(tornado.websocket.WebSocketHandler):
global waiters
def open(self):
print('###FUNCTION CWSHandler.open(self) start')
def on_close(self):
print('###FUNCTION CWSHandler.open(self) close')
def on_message(self, message):
print('###FUNCTION CWSHandler.on_message msg:', message)
settings = {
"cookie_secret": "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=",
"login_url": "/",
}
application = tornado.web.Application(handlers=[
(r'/', MainHandler),
(r'/cws', CWSHandler),
(r"/(.*)", tornado.web.StaticFileHandler,{'path':'./'})
], cookie_secret="bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=")
if __name__ == "__main__":
server = tornado.httpserver.HTTPServer(application)
server.listen(SETTING_CLIENT_LISTEN_PORT)
try:
tornado.ioloop.IOLoop.instance().start()
server.stop()
except KeyboardInterrupt:
print("Keyboard interupt")
pass
finally:
server.stop()
tornado.ioloop.IOLoop.instance().stop()
The problem is with your urls, specifically:
(r"/(.*)", tornado.web.StaticFileHandler,{'path':'./'})
You have mapped r'/(.*)' to {'path': './'}, which is your project directory. So, if a request comes in like localhost:8080/program.py, it will be matched with this - /(.*) and tornado will then look for a file named program.py in your project directory. If it finds it there, it will serve that file.
You should keep all your static files in a separate directory called static (you can name it anything you want, though) inside your project dir. Then map this directory with the desired url.
Example:
(r"/(.*)", tornado.web.StaticFileHandler,{'path': 'static'})
Or better yet, serve that directory under a /static/ url instead of - .*.
(r"/static/(.*)", tornado.web.StaticFileHandler,{'path': 'static'})
Related
Let us create an application server and an admin server. Assume that fusionListener and adminListener contain the application and admin logic we want to expose.
from cherrypy._cpserver import Server
fserver = Server()
fserver.socket_port = 10000
fserver.subscribe()
aserver = Server()
aserver.socket_port = 10001
aserver.subscribe()
And then to start them:
cherrypy.engine.start()
cherrypy.engine.block()
The tree.mount parameters ask for:
the code/ business logic as the first parameter
listening url
config parameters
Here is how that looks for the above servers:
cherrypy.tree.mount(fusionListener, r"/fusion.*",fusionConf)
cherrypy.tree.mount(adminListener, r"/admin.*",adminConf)
But where is the parameter for the server itself - which includes the port being listened to?
This is not a well supported case for CherryPy.
The application selection (cherrypy.tree is basically a map of /path -> App) is done before the request dispatch and... long story short, you could use cherrypy.dispatch.VirtualHost and map you sub applications under a main one (that will route depending on the hostname (which the port can be part of). For the listening on multiple ports, can be done, but again this is a very custom arrangement.
I hope this example is illustrative of a possible way to make such feat:
import cherrypy
from cherrypy import dispatch
from cherrypy._cpserver import Server
class AppOne:
#cherrypy.expose
def default(self):
return "DEFAULT from app ONE!"
#cherrypy.expose
def foo(self):
return "FOO from app ONE"
class AppTwo:
#cherrypy.expose
def default(self):
return "DEFAULT from app TWO!"
#cherrypy.expose
def foo(self):
return "FOO from app TWO"
class Root:
def __init__(self):
self.one = AppOne()
self.two = AppTwo()
def bind_two_servers(app_one_port, app_two_port):
# unsubscribe the default server
cherrypy.server.unsubscribe()
s1 = Server()
s2 = Server()
s1.socket_port = app_one_port
s2.socket_port = app_two_port
# subscribe the server to the `cherrypy.engine` bus events
s1.subscribe()
s2.subscribe()
def start_server():
bind_two_servers(8081, 8082)
cherrypy.engine.signals.subscribe()
cherrypy.engine.start()
cherrypy.engine.block()
config = {
'/': {
'request.dispatch': dispatch.VirtualHost(**{
'localhost:8081': '/one',
'localhost:8082': '/two',
})
}
}
cherrypy.tree.mount(Root(), '/', config)
start_server()
This example will serve AppOne when coming from localhost:8081 and AppTwo when coming from localhost:8082.
The problem is that you can't do multiples cherrypy.tree.mount and expect to route into the different applications using the VirtualHost dispatcher, it assumes that the application resolution is done at that point and is only resolving the path of that application.
Having said all of that... I do not recommend this solution, it can get complicated and it would be better to have some other server in front (like nginx) and serve each path on different processes. This could be an alternative, only if you really really want to avoid any extra server or process in your setup.
I have just made a server (only for localhost) in Python to execute by CGI to execute and try my Python scripts. This is the code of the file that executes the server:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import BaseHTTPServer
import CGIHTTPServer
import cgitb
cgitb.enable() ## This line enables CGI error reporting
server = BaseHTTPServer.HTTPServer
handler = CGIHTTPServer.CGIHTTPRequestHandler
server_address = ("", 8000)
handler.cgi_directories = ["/"]
httpd = server(server_address, handler)
httpd.serve_forever()
When I access some script in the server (http://127.0.0.1:8000/index.py) there is no problem, but when I access the server (http://127.0.0.1:8000/) it shows:
Error response
Error code 403.
Message: CGI script is not executable ('//').
Error code explanation: 403 = Request forbidden -- authorization will not help.
It's like if index files aren't set as default file to access when access a folder instead of a specific file...
I would like to be able to access to http://127.0.0.1/index.py when I access http://127.0.0.1/. Thanks for everything.
Python's built-in HTTP server is extremely basic, so it doesn't include such feature. However you can implement it yourself by subclassing CGIHTTPRequestHandler, probably replacing the is_cgi function.
If you use handler.cgi_directories = ["/cgi"], you can place an index.html file in "/". And of course, if you want a cgi script index.py as default, you can use the index.html for forwarding...
I did try to modify is_cgi function and it's working!
def is_cgi(self):
collapsed_path = _url_collapse_path(self.path)
if collapsed_path == '//':
self.path = '/index.py'
collapsed_path = _url_collapse_path(self.path)
dir_sep = collapsed_path.find('/', 1)
head, tail = collapsed_path[:dir_sep], collapsed_path[dir_sep + 1:]
if head in self.cgi_directories:
self.cgi_info = head, tail
return True
return False
I put this method into this following class:
class CGIHandlerOverloadIndex(CGIHTTPServer.CGIHTTPRequestHandler):
I would like to create a minimal socket server written in python that I can run with my OpenShift account. I searched more than a day, found lots of libraries(tornado, django, twisted, flask, autobahn, gevent) that could be used for this, but I could not manage to implement it for me. (Actually I do not really know the differences between these.)
I looked for lots of tutorials as well, I found an implementation using Tornado:
import tornado.ioloop
import tornado.web
import tornado.websocket
import tornado.template
class MainHandler(tornado.web.RequestHandler):
def get(self):
loader = tornado.template.Loader(".")
self.write('hello world')
class WSHandler(tornado.websocket.WebSocketHandler):
def open(self):
print 'connection opened...'
self.write_message("The server says: 'Hello'. Connection was accepted.")
def on_message(self, message):
self.write_message("The server says: " + message + " back at you")
print 'received:', message
def on_close(self):
print 'connection closed...'
application = tornado.web.Application([
(r'/ws', WSHandler),
(r'/', MainHandler),
(r"/(.*)", tornado.web.StaticFileHandler, {"path": "./resources"}),
])
if __name__ == "__main__":
application.listen(8000)
tornado.ioloop.IOLoop.instance().start()
However I cannot connect to it from a simple html5 websocket client, furthermore I get 503 Service Temporarily Unavailable when I enter my domain.
Could you please either give me a minimal implementation (if possible using tornado, or maybe django) that works if upload it to OpenShift or link me a trustworthy and 100% reliable tutorial? I would be really pleased I can't get my head around this.
You cannot use port address on openshift like that, I suggest you to do this:
ip = os.environ['OPENSHIFT_PYTHON_IP']
port = int(os.environ['OPENSHIFT_PYTHON_PORT'])
application.listen(port , ip)
tornado.ioloop.IOLoop.instance().start()
Check this repo for example: https://github.com/avinassh/openshift-tornado-starter
It doesn't look like OpenShift lets you just run an application like that. You can see a howto guide here: https://github.com/giulivo/openshift-hellotornado
I'm trying to launch a webserver serving several sites under several subdomains.
I'm using Pythen with webapp2 and paste. My Server is behind a router that asigns a static IP adress to the server and forwards port 80. The router itself has no static IP adress assigned by my ISP so I'm using DDNS (lets say example.dlinkddns.com) .
In my folder hierarchy each folder represents a subdomain and is a python module.
Like this:
server/app.py
server/www
server/www/__init__.py
server/test
server/test/__init__.py
they should be reachable via www.mydomain.com and test.mydomain.com
I set *.mydomain.com to be a CNAME for example.dlinkddns.com
This is server/app.py:
import sys
import os
import webapp2
from webapp2_extras import routes
from paste import httpserver
DOMAIN = 'mydomain.com'
class Fallback(webapp2.RequestHandler):
def get(self, *args, **kw):
self.response.write('Fallback...\n'+str(args)+'\n'+str(kw))
def main():
dirs = [name for name in os.listdir(".") if os.path.isdir(name)]
dirs.remove('env') # folder created by package virtualenv - needed for paste
rs = []
for subdomain in dirs:
# import subdomain package
exec('import '+subdomain)
# add routes defined for subdomain
exec('rs += [routes.DomainRoute("'+subdomain+'.'+DOMAIN+'", '+subdomain+'.routes)]')
rs += [routes.DomainRoute("<domain:.*>",[webapp2.Route('/<:.*>',Fallback,name='fallback')])]
app = webapp2.WSGIApplication(rs)
httpserver.serve(app, host='0.0.0.0', port='80')
if __name__ == '__main__':
main()
And this is how my www package looks like:
__init__.py
import webapp2
class MainMain(webapp2.RequestHandler):
def get(self,target):
self.response.write('Hello, webapp2! www.mydomain.com at:'+target)
routes = [
webapp2.Route('/<target>', handler=MainMain, name='main-main')
]
The problem now is, when I visit www.mydomain.com the fallback handler seems to match but MainMain handler should.
The output is
Fallback... () {'domain':'0.0.0.0'}.
It looks like my app wouldn't recognize the domains at all. Same thing happens when I visit example.dlinkddns.com.
I also tried it without the fallback handler but then it only showed me the 404 page for every route and every domain...
I also tried to start the server with
httpserver.serve(app, host='192.168.178.33', port='80')
This is the static assigned IP address of my server in my LAN. The the output changes to
Fallback... () {'domain':'192.168.178.33'}.
What am I doing wrong? Thanks for any help!
I have a Python script that I'd like to be run from the browser, it seem mod_wsgi is the way to go but the method feels too heavy-weight and would require modifications to the script for the output. I guess I'd like a php approach ideally. The scripts doesn't take any input and will only be accessible on an internal network.
I'm running apache on Linux with mod_wsgi already set up, what are the options here?
I would go the micro-framework approach just in case your requirements change - and you never know, it may end up being an app rather just a basic dump... Perhaps the simplest (and old fashioned way!?) is using CGI:
Duplicate your script and include print 'Content-Type: text/plain\n' before any other output to sys.stdout
Put that script somewhere apache2 can access it (your cgi-bin for instance)
Make sure the script is executable
Make sure .py is added to the Apache CGI handler
But - I don't see anyway this is going to be a fantastic advantage (in the long run at least)
You could use any of python's micro frameworks to quickly run your script from a server. Most include their own lightweight servers.
From cherrypy home page documentation
import cherrypy
class HelloWorld(object):
def index(self):
# run your script here
return "Hello World!"
index.exposed = True
cherrypy.quickstart(HelloWorld())
ADditionally python provides the tools necessary to do what you want in its standard library
using HttpServer
A basic server using BaseHttpServer:
import time
import BaseHTTPServer
HOST_NAME = 'example.net' # !!!REMEMBER TO CHANGE THIS!!!
PORT_NUMBER = 80 # Maybe set this to 9000.
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_HEAD(s):
s.send_response(200)
s.send_header("Content-type", "text/html")
s.end_headers()
def do_GET(s):
"""Respond to a GET request."""
s.send_response(200)
s.send_header("Content-type", "text/html")
s.end_headers()
s.wfile.write("<html><head><title>Title goes here.</title></head>")
s.wfile.write("<body><p>This is a test.</p>")
# If someone went to "http://something.somewhere.net/foo/bar/",
# then s.path equals "/foo/bar/".
s.wfile.write("<p>You accessed path: %s</p>" % s.path)
s.wfile.write("</body></html>")
if __name__ == '__main__':
server_class = BaseHTTPServer.HTTPServer
httpd = server_class((HOST_NAME, PORT_NUMBER), MyHandler)
print time.asctime(), "Server Starts - %s:%s" % (HOST_NAME, PORT_NUMBER)
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
print time.asctime(), "Server Stops - %s:%s" % (HOST_NAME, PORT_NUMBER)
What's nice about the microframeworks is they abstract out writing headers and such (but should still provide you an interface to, if required)