Building a simple file server using the SimpleHTTPServer module in Python, however I'm running into issues when trying to get the IP from a connecting client. Here is what I have..
import SimpleHTTPServer
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", 8080), Handler)
print "Serving local directory"
while True:
httpd.handle_request()
print Handler.client_address[0]
When a client connects I get..
AttributeError: class SimpleHTTPRequestHandler has no attribute 'client_address'
I know this is because I haven't instantiated the class yet, but is there another way to get the IP from the client without having to create a handler instance? The client's IP is outputted to the console when a connection is made, I just need a way to grab that IP within my script.
Thanks!
Indeed, the Handler class object is unrelated to specific instances. Set up your own handler class, like this:
import SimpleHTTPServer
import SocketServer
class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def handle_one_request(self):
print(self.client_address[0])
return SimpleHTTPServer.SimpleHTTPRequestHandler.handle_one_request(self)
print("Serving local directory")
httpd = SocketServer.TCPServer(("", 8080), MyHandler)
while True:
httpd.handle_request()
Related
This is interesting. I did a simple script to bind and serve http but I hadn't done this in Python3. I can write a simple server:
import http.server
import socketserver
PORT = 8002
Handler = http.server.SimpleHTTPRequestHandler
#https://docs.python.org/3/library/http.server.html
class MyHandler(http.server.SimpleHTTPRequestHandler):
def __init__(self, request, client_addr, server):
super().__init__(request, client_addr, server)
def do_GET(self, ):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.wfile.write('Hey!'.encode())
httpd = socketserver.TCPServer(("0.0.0.0", PORT), MyHandler)
print("serving at port", PORT)
httpd.serve_forever()
but when I run it, then Ctrl+c, then run it again it says:
OSError: [Errno 98] Address already in use
Why is that if I kill the previous process?
Also, is there any reason other than that that this couldn't be used as a simple, testing webapp for a test server at IP:port/somesamplewebapp - They say "http.server is not recommended for production. It only implements basic security checks." but if it does not need https or extra security... what are the risks?
The operating system prevents, by default, the reuse of an address by a different PID. You can defeat that with the socket option SO_REUSEADDR. However, since you are using the TCPServer class and it has it's own, different, way of specifying that. You can use this code.
import http.server
import socketserver
PORT = 8002
Handler = http.server.SimpleHTTPRequestHandler
#https://docs.python.org/3/library/http.server.html
class MyHandler(http.server.SimpleHTTPRequestHandler):
def __init__(self, request, client_addr, server):
super().__init__(request, client_addr, server)
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.wfile.write('Hey!'.encode())
class MyServer(socketserver.TCPServer):
allow_reuse_address = True # <-- This is what you need
httpd = MyServer(("0.0.0.0", PORT), MyHandler)
print("serving at port", PORT)
httpd.serve_forever()
I was able to start up a simple python server from here
import SimpleHTTPServer
import SocketServer
PORT = 8000
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
httpd.serve_forever()
I was able to use a curl command and see that it does respond with a listing of my directory. I was able to see a 200 GET message pop up on my running server, but no other information. However, is there a way of actually seeing the data in the request come in on the server and parsing it? If someone was to post some information to my server (say in JSON format), how can I actually see all this data.. or even an URL?
Are there any examples which actually build on the above code which show how to handle data coming in? A use case would be someone posting information to the server.
When a GET request comes in (as is sent to your server by curl), SimpleHTTPRequestHandler.do_GET is called behind the scenes. SimpleHTTPRequestHandler is itself a subclass of BaseHTTPRequestHandler.
You can define your own subclass of SimpleHTTPRequestHandler:
class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET():
# your code here
super(MyHandler, self).do_GET()
httpd = SocketServer.TCPServer(("", PORT), MyHandler)
In place of # your code here, you can inspect properties defined by BaseHTTPRequestHandler e.g. self.path and print them or do whatever you want with them.
I want to launch Python HTTPServer on heroku. Note that this is no Python framework. The code snippet is attached below. How will I be able to launch this server on Heroku? I am able to run this server on my local machine. But I want it deployed on Heroku. Please provide insights.
Server Code:
import http.server
from http.server import HTTPServer, BaseHTTPRequestHandler
import socketserver
import threading
PORT = 5001
class myHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.write("Heroku is awesome")
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
try:
server = ThreadedTCPServer(('', PORT), myHandler)
print ('Started httpserver on port ' , PORT)
ip,port = server.server_address
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
allow_reuse_address = True
server.serve_forever()
except KeyboardInterrupt:
print ('CTRL + C RECEIVED - Shutting down the REST server')
server.socket.close()
When heroku runs your process, it defines the environment variable PORT to the internal port you should expose your server on. Your server will then be accessible from the internet on port 80, the default HTTP port.
Python can access environment variables with os.environ.
So you can use:
PORT = environ['PORT']
os.envron docs here
You can read more about how Heroku handles ports here.
Create a Procfile with a single line:
web: python yourscript.py
Used this code to run a python server:
import os
from http.server import SimpleHTTPRequestHandler, HTTPServer
os.chdir('c:/users/owner/desktop/tom/tomsEnyo2.5-May27')
server_address = ('', 8000)
httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)
httpd.serve_forever()
How to make it stop?
Your question is ambiguous - if your running the server via shell i.e. python myscript.py, simply press crtl + C.
If you want to close it elegantly using code, you must decide on some condition, or point, or exception to call it shutdown. You can add a block and call httpd.shutdown() - as HttpServer itself is a SocketServer.TCPSServer subclass:
The first class, HTTPServer, is a SocketServer.TCPServer subclass, and
therefore implements the SocketServer.BaseServer interface. It creates
and listens at the HTTP socket, dispatching the requests to a handler.
So the BaseServer has a method shutdown(), hence being a subclass HttpServer has it too.
for example:
import os
from http.server import SimpleHTTPRequestHandler, HTTPServer
os.chdir('c:/users/owner/desktop/tom/tomsEnyo2.5-May27')
server_address = ('', 8000)
try:
httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)
httpd.serve_forever()
except Exception:
httpd.shutdown()
Helpful relevant question -
How do I shutdown an HTTPServer from inside a request handler in Python?
How to stop BaseHTTPServer.serve_forever() in a BaseHTTPRequestHandler subclass?
You can send a SIGTERM signal from the handler thread if you are ok with killing the whole process:
os.kill(os.getpid(), signal.SIGTERM)
If you need the Python HTTP server in a unit test then it is advisable to run it in a separate thread and stop it from another one, like this:
import unittest
from threading import Thread
from http.server import HTTPServer
class TestWithHTTP(unittest.TestCase):
"""
My unit test that needs a HTTP server
NOTE: skeleton code
"""
def setUp(self):
# you need to provide the host, port and request handler class
self.myserver = HTTPServer((host, port), HandlerClass)
# start HTTP server in another thread
httpthread = Thread(target=self.myserver.serve_forever)
httpthread.start()
# ... any other setup operations ...
def test_something(self):
# ... your unit testing code ...
pass
def tearDown(self):
# shut down the server from yet another thread
killerthread = Thread(target = self.myserver.shutdown)
killerthread.start()
Just use ^C (control+c) to shut down python server.
I've created a class for a server with the declaration:
class myServer(socketserver.BaseRequestHandler):
def handle(self):
pass
And started it with:
someServer = socketserver.UDPServer((HOST, PORT), myServer)
someServer.serve_forever()
My question is: how can I get the server to shutdown itself? I've seen it has a base class (of a base class) called BaseServer with a shutdown method. It can be called on someServer with someServer.shutdown() but this is from the outside of the server itself.
By using threads. Serving by one thread and going via another after your timeout.
Consider this working example. Modify it for your UDPServer
import threading
import time
import SimpleHTTPServer
import SocketServer
PORT = 8000
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
def worker():
# minimal web server. serves files relative to the
print "serving at port", PORT
httpd.serve_forever()
def my_service():
time.sleep(3)
print "I am going down"
httpd.shutdown()
h = threading.Thread(name='httpd', target=worker)
t = threading.Thread(name='timer', target=my_service)
h.start()
t.start()
You could use twisted. Its about the best networking lib for python, here is an example of a UDP server here is (taken from the twisted documentation) the simplest UDP server ever written;
#!/usr/bin/env python
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
# See LICENSE for details.
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
# Here's a UDP version of the simplest possible protocol
class EchoUDP(DatagramProtocol):
def datagramReceived(self, datagram, address):
self.transport.write(datagram, address)
def main():
reactor.listenUDP(8000, EchoUDP())
reactor.run()
if __name__ == '__main__':
main()
You can then close this down by calling self.transport.loseConnection() When you are ready or a specific event happens.
The server instance is available as self.server in the handler class. So you can call self.server.shutdown() in the handle method.