Python Web Server - python

I want a simple python web server for the following use case:
I want to write a simple server that will accept HTTP requests from my application running on Google App Engine.
The server will accept HTTP requests, and then send iphone notifications. (Basically, I need this extra server to account for the lack of socket support in google app engine).
I guess I need the server to be able to maintain this persistent connection with Apple's Push Notification Service. So I'll need to have some sort of thread always open for this. So I need some sort of web server that can accept the request pass it off to the other thread with the persistent connection to APNS.
Maybe multiple processes and one of pythons queuing tools to communicate between them? Accept the HTTP request, then enqueue a message to the other process?
I was wondering what someone with a bit of experience would suggest. I'm starting to think that maybe even writing my own simple server is a good option (http://fragments.turtlemeat.com/pythonwebserver.php).

One option would be the (appropriately named) SimpleHTTPServer, which is part of the Python standard library. Another, more flexible but more complicated option would be to write your server in Twisted.

I've been writing simple http servers using gevent and bottle -- an example:
#!/usr/bin/env python
import gevent.monkey
gevent.monkey.patch_all()
import bottle
bottle.debug(True)
import gevent.wsgi
from bottle import route, run, request, response, static_file, abort
#route('/echo')
def echo():
s = request.GET.get('s', 'o hai')
return '<html><head><title>echo server</title></head><body>%s</body></html>\r\n' % (s)
#route('/static/:filename')
def send_static(filename):
root = os.getcwd() + '/static'
return static_file(filename, root=root)
if __name__ == '__main__':
app = bottle.app()
wsgi_server = gevent.wsgi.WSGIServer(('0.0.0.0', 8000), app)
print 'Starting wsgi search on port 8000'
wsgi_server.serve_forever()
So you could write a simple server that sticks a job into a Queue (see gevent.queue) and have another worker greenlet that handles reading requests from the queue and processing them...

Related

Python Twisted Authentication Without HTTP Authentication

I'm setting up a Flask server, and want to use a Twisted ReverseProxyResource to proxy over another local server. In Flask, I have a current_user.is_authenticated boolean which I use to protect pages. How can I lock the ReverseProxyResource using this variable, so that it cannot be accessed when a user is logged out? The twisted.web.guard module requires me to set up another HTTP authentication system entirely, and the library doesn't seem to have any other built-in solution.
I've set up some demo code, (based off a previous question) attempting to place the Flask server inside of the Twisted reactor. I'm using the ReverseProxyResource to allow for two-way communication with a Shellinabox server on port 4200.
from flask import Flask
from twisted.internet import reactor
from twisted.web.proxy import ReverseProxyResource
from twisted.web.resource import Resource
from twisted.web.server import Site
from twisted.web.wsgi import WSGIResource
app = Flask(__name__)
#app.route('/example')
def index():
return 'Flask within Twisted?'
flask_site = WSGIResource(reactor, reactor.getThreadPool(), app)
root = Resource()
site_example = ReverseProxyResource('localhost', 4200, b'')
root.putChild(b'ssh', site_example)
reactor.listenTCP(8081, Site(root))
reactor.run()
I'd be okay switching to another reverse proxy, but only Twisted has worked so far. I'm also not wanting to switch to the Klein framework due to what I already have established in Flask.

Python HTTP Server - Create without using HTTP modules

Can I create a HTTP server without using
python -m http.server [port number]
Using an old school style with sockets and such.
Latest code and errors...
import socketserver
response = """HTTP/1.0 500 Internal Server Error
Content-type: text/html
Invalid Server Error"""
class MyTCPHandler(socketserver.BaseRequestHandler):
"""
The RequestHandler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
self.request.sendall(response)
if __name__ == "__main__":
HOST, PORT = "localhost", 8000
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
TypeError: 'str' does not support the buffer interface
Yes, you can, but it's a terrible idea -- in fact, even http.server is at best a toy implementation.
You're better off writing whatever webapp you want as a standard WSGI application (most Python web frameworks do that -- Django, Pyramid, Flask...), and serving it with one of the dozens of production-grade HTTP servers that exist for Python.
uWSGI (https://uwsgi-docs.readthedocs.org/en/latest/) is my personal favorite, with Gevent a close second.
If you want more info about how it's done, I recommend that you read the source code to the CherryPy server (http://www.cherrypy.org/). While not as powerful as the aforementioned uWSGI, it's a good reference implementation written in pure Python, that serves WSGI apps through a thread pool.
Sure you can, and servers like Tornado already do it this way.
For simple test servers which can do only HTTP/1.0 GET requests and handle only a single request at a time it should not be that hard once you understood the basics of the HTTP protocol. But if you care even a bit about performance it gets complex fast.

How to have one Flask app listen on two different ports?

Is it possible to have a single flask app with routes on two different ports? My Flask app needs to listen for webhooks and due to some security biz it can't receive foreign POST requests on the default port. Is it possible to do something like this?
#app.route('/hook/<sourcename>', methods=["POST"], port=5051)
def handle_hook(sourcename):
print 'asdf'
If you don't need any socket code inside C plugins, gevent could help, e.g. with
import gevent
from gevent.pywsgi import WSGIServer
app = Flask(__name__)
https_server = WSGIServer((HOST, HTTPS_PORT), app, keyfile=PRIVKEY, certfile=CERT)
https_server.start()
http_server = WSGIServer((HOST, HTTP_PORT), app)
http_server.start()
while True:
gevent.sleep(60)
A server by default only listens to a single port. Wouldn't it make more sense, since the additional port requires additional functionality, to implement a front-end server on the second port that proxies the POST request locally? There are many well-documented ways to do this such as this one

Combining websockets and WSGI in a python app

I'm working on a scientific experiment where about two dozen test persons play a turn-based game with/against each other. Right now, it's a Python web app with a WSGI interface. I'd like to augment the usability with websockets: When all players have finished their turns, I'd like to notify all clients to update their status. Right now, everyone has to either wait for the turn timeout, or continually reload and wait for the "turn is still in progress" error message not to appear again (busy waiting, effectively).
I read through multiple websocket libraries' documentation and I understand how websockets work, but I'm not sure about the architecture for mixing WSGI and websockets: Can I have a websockets and a WSGI server in the same process (and if so, how, using really any websockets library) and just call my_websocket.send_message() from a WSGI handler, or should I have a separate websockets server and do some IPC? Or should I not mix them at all?
edit, 6 months later: I ended up starting a separate websockets server process (using Autobahn), instead of integrating it with the WSGI server. The reason was that it's much easier and cleaner to separate the two of them, and talking to the websockets server from the WSGI process (server to server communication) was straight forward and worked on the first attempt using websocket-client.
Here is an example that does what you want:
https://github.com/tavendo/AutobahnPython/tree/master/examples/twisted/websocket/echo_wsgi
It runs a WSGI web app (Flask-based in this case, but can be anything WSGI conforming) plus a WebSocket server under 1 server and 1 port.
You can send WS messages from within Web handlers. Autobahn also provides PubSub on top of WebSocket, which greatly simplifies the sending of notifications (via WampServerProtocol.dispatch) like in your case.
http://autobahn.ws/python
Disclosure: I am author of Autobahn and work for Tavendo.
but I'm not sure about the architecture for mixing WSGI and websockets
I made it
use WSocket
Simple WSGI HTTP + Websocket Server, Framework, Middleware And App.
Includes
Server(WSGI) included - works with any WSGI framework
Middleware - adds Websocket support for any WSGI framework
Framework - simple Websocket WSGI web application framework
App - Event based app for Websocket communication
When external server used, some clients like Firefox requires http 1.1 Server. for Middleware, Framework, App
Handler - adds Websocket support to wsgiref(python builtin WSGI server)
Client -Coming soon...
Common Features
only single file less than 1000 lines
websocket sub protocol supported
websocket message compression supported (works if client asks)
receive and send pong and ping messages(with automatic pong sender)
receive and send binary or text messages
works for messages with or without mask
closing messages supported
auto and manual close
example using bottle web framework and WSocket middleware
from bottle import request, Bottle
from wsocket import WSocketApp, WebSocketError, logger, run
from time import sleep
logger.setLevel(10) # for debugging
bottle = Bottle()
app = WSocketApp(bottle)
# app = WSocketApp(bottle, "WAMP")
#bottle.route("/")
def handle_websocket():
wsock = request.environ.get("wsgi.websocket")
if not wsock:
return "Hello World!"
while True:
try:
message = wsock.receive()
if message != None:
print("participator : " + message)
wsock.send("you : "+message)
sleep(2)
wsock.send("you : "+message)
except WebSocketError:
break
run(app)

Combine SimpleXMLRPCServer and BaseHTTPRequestHandler in Python

Because cross-domain xmlrpc requests are not possible in JavaScript
I need to create a Python app which exposes both some HTML through HTTP and an XML-RPC service on the same domain.
Creating an HTTP request handler and SimpleXMLRPCServer in python is quite easy,
but they both have to listen on a different port, which means a different domain.
Is there a way to create something that will listen on a single port on the localhost
and expose both the HTTPRequestHandler and XMLRPCRequest handler?
Right now I have two different services:
httpServer = HTTPServer(('localhost',8001), HttpHandler);
xmlRpcServer = SimpleXMLRPCServer(('localhost',8000),requestHandler=RequestHandler)
Update
I cannot install Apache on the device
The hosted page will be a single html page
The only client will be the device on witch the python service runs itself
Both of them subclass of SocketServer.TCPServer. There must be someway to refactor them so that once server instance can dispatch to both.
An easier alternative may be to keep the HTTPServer in front and proxy XML RPC to the SimpleXMLRPCServer instance.
The solution was actually quite simple, based on Wai Yip Tung's reply:
All I had to do was keep using the SimpleXMLRPCServer instance,
but modify the handler:
class RequestHandler(SimpleXMLRPCRequestHandler):
rpc_paths = ('/RPC2',)
def do_GET(self):
#implementation here
This will cause the handler to respond to GET requests as well as the original POST (XML-RPC) requests.
Using HTTPServer for providing contents is not a good idea. You should use a webserver like Apache and use Python as CGI (or a more advanced interface like mod_wsgi).
Then, the webserver is running on one port and you can server HTML directly over the webserver and write as many CGI scripts as you like in Python, as example one for XMLRPC requests using CGIXMLRPCRequestHandler.
class MyFuncs:
def div(self, x, y) : return x // y
handler = CGIXMLRPCRequestHandler()
handler.register_function(pow)
handler.register_function(lambda x,y: x+y, 'add')
handler.register_introspection_functions()
handler.register_instance(MyFuncs())
handler.handle_request()

Categories

Resources