Interfacing BaseHttpServer to WSGI in python - python

I am taking a python course where they use BaseHTTPServer. The code they start with is here
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
class webServerHandler(BaseHTTPRequestHandler):
def do_GET(self):
try:
if self.path.endswith("/hello"):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
message = ""
message += "<html><body>Hello!</body></html>"
self.wfile.write(message)
print message
return
except IOError:
self.send_error(404, 'File Not Found: %s' % self.path)
def main():
try:
port = 8080
server = HTTPServer(('', port), webServerHandler)
print "Web Server running on port %s" % port
server.serve_forever()
except KeyboardInterrupt:
print " ^C entered, stopping web server...."
server.socket.close()
if __name__ == '__main__':
main()
I am using python anywhere and there the only possibility to get an application onto the internet is to use an wsgi interface.
A configuration file for the wsgi interface looks like this:
import sys
path = '<path to app>'
if path not in sys.path:
sys.path.append(path)
from app import application
application could be something like this:
def application(environ, start_response):
if environ.get('PATH_INFO') == '/':
status = '200 OK'
content = HELLO_WORLD
else:
status = '404 NOT FOUND'
content = 'Page not found.'
response_headers = [('Content-Type', 'text/html'), ('Content-Length', str(len(content)))]
start_response(status, response_headers)
yield content.encode('utf8')
HELLO_WORLD would be a string with html content.
I cannot just point to port 8080 as in the example. In order to use python anywhere I do have to interface both. I reckoned it could be possible that the wsgi is derived from BaseHTTPServer so it might be possible to interface them and to use my course on pythonanywhere.com
It is clear I have to get rid in the code in the main function and use the application function instead. But I am not exactly getting how this works. I get a callback (start_response) which I call and then I yield the content? How can I combine this with the webServerHandler class?
If this would be possible it should in theory work as well for the google app engine. I found a very complex example here where BaseHTTPServer is used but this is too complex for me yet.
Is it possible to do this and if yes could someone give me a hint how to do this and provide me with some basic start code?

So WSGI is a specification that defines an interface between a request and a webapp. ie. when it receives a http request, it will pass it along to the webapp in a standardized way as described in the specification (eg: it must set this environment variable, it must pass this argument, it must make this call etc).
On the other hand, BaseHTTPServer both defines an interface and also has code that actually serves web requests.
This is a little used interface that is implemented almost exclusively by SimpleHTTPServer from the python2 standard library (or http.server in python3), and the server is not intended for anything production-ready.
This is because SimpleHTTPServer was designed mainly for developing locally. For example, it helps you get past js cross origin request problems when testing on localhost.
Nowadays, WSGI has become the de facto standard for python webapps, and so most websites written in python separate out the server / interface-y functionality that receives and implements the WSGI requirements from the webapp-y stuff.
In your code, you have a single piece of code that does both the "webapp-y" stuff and also the "process the http request / interface-y" stuff. This is not wrong, and is great for getting some basic understanding of how servers process http requests etc.
So my suggestion would be:
if your class is going to start using any python webapp frameworks soon anywahs, (eg: django, flask, , bottle, web2py, cherrypy etc), then you could potentially just wait till then to use pythonanywhere.
if your class is focused on digging into the nitty gritty of servers, you could refactor out the "webapp-y" layer from your code, and just use the "webapp-y" layer on PythonAnywhere. Locally, you would start the "server/interface-y" stuff that then imports your "webapp-y" to generate a response. If you successfully do this, then congrats! You have (kind of) just written a server that supports WSGI.

Related

How to serve Flask With Http Server [duplicate]

This question already has answers here:
Are a WSGI server and HTTP server required to serve a Flask app?
(3 answers)
How to serve static files in Flask
(24 answers)
How to run functions in parallel?
(8 answers)
Closed 3 years ago.
I would like to develop an app that uses both Flask and httpd.
Flask publishes HTML-related files, and httpd publishes files in local files.
It is for browsing local files published in httpd from Flask HTML.
Though the port numbers of Flask and httpd are different, it seems that httpd server side is not working.
Connection refused error occurs when connecting to httpd server.
Added the intention of the question.
I want to run Flask's built-in web server and HTTPServer simultaneously from a script.
I just want to be able to see myself, not to expose it to the network.
I'm looking for a mechanism that can be completed with the app.py script without using WSGI.
Added additional information to the question.
This question uses Flask and Python's HTTPServer, but using NodeJS's HTTPServer instead of HTTPServer seems to work well.
(Comment out run())
I would like to complete in Python if possible without using NodeJS HTTPServer.
https://www.npmjs.com/package/http-server
C:\Users\User\Videos>http-server
Starting up http-server, serving ./
Available on:
http://127.0.0.1:8080
Hit CTRL-C to stop the server
...
version
Flask==1.0.2
Python 3.7
Can I not start each server with the following code?
templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<video src="http://localhost:8080/video.mp4"></video>
</body>
</html>
python(app.py)
from http.server import SimpleHTTPRequestHandler, HTTPServer
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def hello_world():
return render_template('index.html')
class Handler(SimpleHTTPRequestHandler):
def __init__(self, *args, directory=None, **kwargs):
super().__init__(*args,
directory=r'C:\Users\User\Videos',
**kwargs)
def run(server_class=HTTPServer, handler_class=Handler):
server_address = ('localhost', 8000)
httpd = server_class(server_address, handler_class)
httpd.serve_forever()
if __name__ == '__main__':
app.run(host='localhost', port=5000)
run()
It may not have been transmitted well. I'm sorry.
Thank you very much.
Can I not start each server with the following code?
Yes, there are many other ways.
WSGI
wsgi, which stands for Web Server Gateway Interface is defined in PEP 333:
This document specifies a proposed standard interface between web
servers and Python web applications or frameworks, to promote web
application portability across a variety of web servers.
framework side
flask, django and many other frameworks all implement this interface. So when you write an app in flask, app implements wsgi so any web server that knows how to serve a wsgi app can serve it.
web server side
There are many choices and you can find more at wsgi.org:
gunicorn
uWSGI
...
Basically, you can choose any of these to start your server and use httpd to proxy requests to it. Or you can use mod_wsgi:
mod_wsgi is an Apache module that embeds a Python application within
the server and allow them to communicate through the Python WSGI
interface as defined in the Python PEP 333.
Note
The bundled server in flask is not suitable for production use, you can see this question for more details.
For Updated Question
I want to run Flask's built-in web server and HTTPServer
simultaneously from a script.
Just Run Shell Command
You can start another process and call shell command using Popen:
if __name__ == '__main__':
p = Popen(['python -m http.server'], shell=True)
app.run(host='localhost', port=5000)
Use whatever command you like, you can even start a node http server here.
Use Thread/Process
You can start http server in another thread or process, here I use threading for example:
if __name__ == '__main__':
from threading import Thread
Thread(target=run, daemon=True).start()
app.run(host='localhost', port=5000)
Use Flask To Serve File
Instead of starting two servers binding to two ports, you can actually use flask to serve file as well. In this way, you only start one server binding to one port:
#app.route('/videos/<path:filename>')
def download_file(filename):
return send_from_directory(r'C:\Users\User\Videos',
filename, as_attachment=True)
You can see documentation for more details.
app.run() is a blocking operation. The below lines won't be interpreted.
Run your apps from separate files or in different thread/process.

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 write a message in SimpleHTTPServer

I'm relatively new to Python. I am trying to run a simple server using python. I successfully did this, but I want to have a message such as "Hello World" when I run the server from my browser.
It posts my directory when I run the program and says "Directory listing for/" at the top. Is there a way to add more text on this page?
How would I do this?
import sys
import BaseHTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
HandlerClass = SimpleHTTPRequestHandler
ServerClass = BaseHTTPServer.HTTPServer
Protocol = "HTTP/1.0"
if sys.argv[1:]:
port = int(sys.argv[1])
else:
port = 8000
server_address = ('127.0.0.1', port)
HandlerClass.protocol_version = Protocol
httpd = ServerClass(server_address, HandlerClass)
sa = httpd.socket.getsockname()
print "Serving HTTP on", sa[0], "port", sa[1], "..."
httpd.serve_forever()
When you implement such a httpserver and browse it, the do_GET method of the SimpleHTTPRequestHandler is called. And by default it will searches the directory your script is in for index.html or index.htm. If there is no such file, the directory will be displayed.
So if you want to display contents rather than the directory. You should add a file index.html or index.htm in your directory. And writes the contents you want to display in the file.
For more please refer the doc.
You are using SimpleHTTPServer, and while its great, you would have to use CGI for interaction. This answer does not answer your exact question, but I believe it will allow you to do the same with, with ease.
In Python, we use WSGI servers to interact with websites. The reason we do this, is because WSGI scales and can handle a lot more than CGI or Common Gateway Interface. You can take a look # WSGI, here.
Armin Ronacher wrote this, and he is the author of two popular Python frameworks, Flask and Werkzueg. If you intend to continue learning Python web development, you will meet these frameworks soon.
I realize that this does not answer your question per-se. But, it will allow you to get the same thing, and will give you a foundation that can help you with popular frameworks.

Python Web Server

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...

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