I have used mod_wsgi to create a web server that can be called locally. Now I just found out I need to change it so it runs through the Apache server. I'm hoping to do this without rewriting my whole script.
from wsgiref.simple_server import make_server
class FileUploadApp(object):
firstcult = ""
def __init__(self, root):
self.root = root
def __call__(self, environ, start_response):
if environ['REQUEST_METHOD'] == 'POST':
post = cgi.FieldStorage(
fp=environ['wsgi.input'],
environ=environ,
keep_blank_values=True
)
body = u"""
<html><body>
<head><title>title</title></head>
<h3>text</h3>
<form enctype="multipart/form-data" action="http://localhost:8088" method="post">
</body></html>
"""
return self.__bodyreturn(environ, start_response,body)
def __bodyreturn(self, environ, start_response,body):
start_response(
'200 OK',
[
('Content-type', 'text/html; charset=utf8'),
('Content-Length', str(len(body))),
]
)
return [body.encode('utf8')]
def main():
PORT = 8080
print "port:", PORT
ROOT = "/home/user/"
httpd = make_server('', PORT, FileUploadApp(ROOT))
print "Serving HTTP on port %s..."%(PORT)
httpd.serve_forever() # Respond to requests until process is killed
if __name__ == "__main__":
main()
I am hoping to find a way to make it possible to avoid making the server and making it possible to run multiple instances of my script.
The documentation at:
http://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines
explains what mod_wsgi is expecting to be given.
If you also read:
http://blog.dscpl.com.au/2011/01/implementing-wsgi-application-objects.html
you will learn about the various ways that WSGI application entry points can be constructed.
From that you should identify that FileUploadApp fits one of the described ways of defining a WSGI application and thus you only need satisfy the requirement that mod_wsgi has of the WSGI application object being accessible as 'application'.
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'm trying to run python on the web to do some CSS/JSS extraction from websites. I'm using mod_wsgi as my interface for python. I've been following this website to get an idea on getting started.
The below is their sample code.
#! /usr/bin/env python
# Our tutorial's WSGI server
from wsgiref.simple_server import make_server
def application(environ, start_response):
# Sorting and stringifying the environment key, value pairs
response_body = ['%s: %s' % (key, value)
for key, value in sorted(environ.items())]
response_body = '\n'.join(response_body)
status = '200 OK'
response_headers = [('Content-Type', 'text/plain'),
('Content-Length', str(len(response_body)))]
start_response(status, response_headers)
return [response_body]
# Instantiate the WSGI server.
# It will receive the request, pass it to the application
# and send the application's response to the client
httpd = make_server(
'localhost', # The host name.
8051, # A port number where to wait for the request.
application # Our application object name, in this case a function.
)
# Wait for a single request, serve it and quit.
httpd.handle_request()
While this runs fine with python 2.7, I can't get it to run on Python 3. For my CSS/JSS extraction, I have modified the above code and put in my own functionalities which use BeautifulSoup and urllib3. While for using those modules I need python 3, for the WSGI code I need python 2.7. Hence, I can't merge the two. When trying to run BS and urllib in python3, I get an error. But when I try to run the WSGI code with python3, I'm just unable to load the webpage.
Any help would be greatly appreciated! Any workarounds, or suggestions as well.
I'm really confusing about multiple thread in mod_wsgi, even after reading this document
The main problem is that, how does mod_wsgi call my python scripts?
To make my question clear, i will conclude it to questions below
Suppose I have server configured like this:
WSGIDaemonProcess XXX.com processes=12 threads=20 display-name=%{GROUP}
WSGIProcessGroup XXX.com
WSGIScriptAlias /sign /XXX/Http/upload.wsgi
And I'm using prefork MPM
And my /XXX/Http/upload.wsgi looks like this
class app(object):
def __init__(self):
pass
def __call__(self, environ, start_response):
temp_unsign = tempfile.mkdtemp()
temp_signed = tempfile.mkdtemp()
try:
response_headers = [('Content-type', 'text/plain;charset=UTF-8'),('Content-Length', str(len('123')))]
status = '200 OK'
start_response(status, response_headers)
return ['123']
finally:
shutil.rmtree(temp_unsign)
shutil.rmtree(temp_signed)
application = app()
Them my questions are:
If there're 5 requests from different IP at the same time, how many app instances will be there? One instance ? Or one instance per request
What if there're 5 requests from same IP and same computer at the same time?
Does all 5 __call__ methods run in 5 different threads?
I ask this because I always get error No such directory when execute shutil.rmtree.
And of course, i can't understand how does mod_wsgi actually work in the matter of multiple thread
I want to run 2 servers of cherry py on different ports and with a different application.
I manage to run them both, but how do i connect between the app's and the servers ?
I want to be able to go to
http://127.0.0.1:3141/
and get server1
and to
http://127.0.0.1:3145/
and get server2
cherrypy docs example for multiple servers is not good enough for me to understand how to do this.
here it is Multiple servers/ports
my code
import cherrypy
class App1(object):
#cherrypy.expose
def index(self):
return ('server1')
class App2(object):
#cherrypy.expose
def index(self):
return ('server2')
cherrypy.server.unsubscribe()
server1 = cherrypy._cpserver.Server()
server1.socket_port=3141
server1._socket_host="127.0.0.1"
server1.thread_pool=2
server1.subscribe()
server2 = cherrypy._cpserver.Server()
server2.socket_port=3145
server2._socket_host="127.0.0.1"
server2.thread_pool=2
server2.subscribe()
cherrypy.engine.start()
cherrypy.engine.block()
If your apps need to (or can) be served from different paths (e. g. http://127.0.0.1:3141/app1 and http://127.0.0.1:3145/app2), just use tree.mount() for each app. If both apps must be served from the root path, look at VirtualHost for an idea.
After tweaking for a while I was not able to mount each app to a specific port.
The behavior was that each port was responding to each app, so I added a tool to filter port on each app as shown in the example below:
import cherrypy
from cherrypy._cpserver import Server
#cherrypy.tools.register('before_handler')
def port_filter():
if cherrypy.request.app.root.request_port != cherrypy.request.local.port:
raise cherrypy.NotFound()
class App1(object):
def __init__(self, request_port):
self.request_port = request_port
#cherrypy.expose
#cherrypy.tools.port_filter()
def index(self):
return "Hello world from app1"
class App2(object):
def __init__(self, request_port):
self.request_port = request_port
#cherrypy.expose
#cherrypy.tools.port_filter()
def index(self):
return "Hello world from app2"
class MyServer(Server):
def __init__(self, host, port, thread_pool=10):
Server.__init__(self)
self.socket_port = port
self._socket_host = host
self.thread_pool = thread_pool
self.subscribe()
if __name__ == '__main__':
# Unsubscribe default server
cherrypy.server.unsubscribe()
# Setup server for each port
MyServer(host='0.0.0.0', port=80)
MyServer(host='0.0.0.0', port=8080)
# Mount applications to specific port
cherrypy.tree.mount(App1(80), "/app1")
cherrypy.tree.mount(App2(8080), "/app2")
# Start!
cherrypy.engine.start()
cherrypy.engine.block()
I think you need two different directory. In each directory/app you put a config file for the app.
For example i have something like this:
[global]
server.socket_host = "ip_address"
server.socket_port = 8080
server.thread_pool = 10
[/]
tools.staticdir.root = "/path/to/your/app"
tools.encode.on = True
tools.decode.on = True
Have a look here
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)