I'm building an Http file server using python so I'm using http.server python built-in package like the following
from http.server import HTTPServer, BaseHTTPRequestHandler
from io import BytesIO
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(b'Hello, world!')
def do_POST(self):
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
self.send_response(200)
self.end_headers()
response = BytesIO()
response.write(b'This is POST request. ')
response.write(b'Received: ')
response.write(body)
self.wfile.write(response.getvalue())
httpd = HTTPServer(('255.255.255.255', 8000), SimpleHTTPRequestHandler)
httpd.serve_forever()
so I've read that this package is not recommended for production. It only implements basic security checks.
are there any alternatives or a better way of doing this?
Python library is not intended to provide a high performance and highly secure http server. It just allows to build both simply and quickly an acceptable http server meeting your functional requirements. If you want to use it in production, just hide it behind an Apache or nginx reverse proxy. That way, only the secure proxy will be exposed to internet.
That is what is commonly done for professional grade Tomcat application servers.
Related
I have this code
httpd = HTTPServer(('127.0.0.1', 8000),SimpleHTTPRequestHandler)
httpd.handle_request()
httpd.handle_request() serves one request and then kills the server like intended. I want to capture this request as a variable so I can parse it later on.
Something like
Request_Variable = httpd.handle_request()
*This code above doesn't work. But I'm looking for something similar
Thanks
You could extend the BaseHTTPRequestHandler and implement your own do_GET (resp. do_POST) method which is called when the server receives a GET (resp. POST) request.
Check out the documentation to see what instance variables a BaseHTTPRequestHandler object you can use. The variables path, headers, rfile and wfile may be of your interest.
from http.server import BaseHTTPRequestHandler, HTTPServer
class MyRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
print(self.path)
def do_POST(self):
content_length = int(self.headers.get('Content-Length'))
print(self.rfile.read(content_length))
httpd = HTTPServer(('127.0.0.1', 8000), MyRequestHandler)
httpd.handle_request()
# make your GET/POST request
How can I keep my Python HTTP server connected(streaming) to my browser in real time?
(Update image to infinity) Like raspberry pi's motion eye
class MyHttpRequestHandler(http.server.SimpleHTTPRequestHandler):
def _set_response(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.send_header("Connection", "keep-alive")
self.send_header("keep-alive", "timeout=999999, max=99999")
self.end_headers()
def do_GET(self):
#self.send_response(204)
#self.end_headers()
if self.path == '/':
self.path = 'abc.jpg'
return http.server.SimpleHTTPRequestHandler.do_GET(self)
# Create an object of the above class
handler_object = MyHttpRequestHandler
PORT = 8000
my_server = socketserver.TCPServer(("", PORT), handler_object)
# Star the server
my_server.serve_forever()
Just keep writing, as in:
while True:
self.wfile.write(b"data")
This however won't get you into eventstream / server sent events territory, without using helper external libraries, as far as I'm aware.
I came across the same issue, I then found by chance (after much debugging) that you need to send linebreaks (\r\n or \n\n) to have the packets sent:
import http.server
import time
class MyHttpRequestHandler(http.server.BaseHTTPRequestHandler):
value = 0
# One can also set protocol_version = 'HTTP/1.1' here
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.send_header("Connection", "keep-alive")
self.end_headers()
while True:
self.wfile.write(str(self.value).encode())
self.wfile.write(b'\r\n') # Or \n\n, necessary to flush
self.value += 1
time.sleep(1)
PORT = 8000
my_server = http.server.HTTPServer(("", PORT), MyHttpRequestHandler)
# Start the server
my_server.serve_forever()
This enables you to send Server-sent Events (SSE) or HTTP long poll, or even json/raw http streams with the http.server library.
As the comment in the code says, you can also set the protocol version to HTTP/1.1 to enable keepalive by default. If you do so, you will have to specify Content-Length for every sent packet, otherwise the connection will never be terminated.
It is probably best to combine this with a threaded server to allow concurrent connections, as well as maybe setting a keepalive on the socket itself.
I am putting together an http-post server client example in order to send and request data from a client to a server that handle multiple connections. I am using the HTTPServer module from the standard library. The code seems to work fine, but the communication slows down randomly. I have checked the communication traffic using Wireshark and I can see some strange messages going on.
I have checked different solutions on internet, but I have not found anything unusual in my code.
The code for the client it is just a simple http post request
Server code:
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
data = {
'ids': [5, 6]
}
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps(data).encode())
return
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
"""Handle requests in a separate thread."""
test = HTTPServer((SV_HOST, SV_PORT), Handler)
test.timeout = 5
print('Starting server, use <Ctrl-C> to stop')
test.serve_forever()
Here are the Wireshark messages that I see:
I would appreciate if someone can clarify what I am doing wrong, if there is something wrong. Is "TCP segment of a reassembled PDU" normal?
I have written this HTTP web server in python which simply sends reply "Website Coming Soon!" to the browser/client, but I want that this web server should sends back the URL given by the client, like if I write
http://localhost:13555/ChessBoard_x16_y16.bmp
then server should reply back the same url instead of "Website Coming Soon!" message.
please tell how can I do this?
Server Code:
import sys
import http.server
from http.server import HTTPServer
from http.server import SimpleHTTPRequestHandler
#import usb.core
class MyHandler(SimpleHTTPRequestHandler): #handles client requests (by me)
#def init(self,req,client_addr,server):
# SimpleHTTPRequestHandler.__init__(self,req,client_addr,server)
def do_GET(self):
response="Website Coming Soon!"
self.send_response(200)
self.send_header("Content-type", "application/json;charset=utf-8")
self.send_header("Content-length", len(response))
self.end_headers()
self.wfile.write(response.encode("utf-8"))
self.wfile.flush()
print(response)
HandlerClass = MyHandler
Protocol = "HTTP/1.1"
port = 13555
server_address = ('localhost', port)
HandlerClass.protocol_version = Protocol
try:
httpd = HTTPServer(server_address, MyHandler)
print ("Server Started")
httpd.serve_forever()
except:
print('Shutting down server due to some problems!')
httpd.socket.close()
You can do what you're asking, sort of, but it's a little complicated.
When a client (e.g., a web browser) connects to your web server, it sends a request that look like this:
GET /ChessBoard_x16_y16.bmp HTTP/1.1
Host: localhost:13555
This assumes your client is using HTTP/1.1, which is likely true of anything you'll find these days. If you expect HTTP/1.0 or earlier clients, life is much more difficult because there is no Host: header.
Using the value of the Host header and the path passed as an argument to the GET request, you can construct a URL that in many cases will match the URL the client was using.
But it won't necessarily match in all cases:
There may be a proxy in between the client and your server, in which case both the path and hostname/port seen by your code may be different from that used by the client.
There may be packet manipulation rules in place that modify the destination ip address and/or port, so that the connection seen by your code does not match the parameters used by the client.
In your do_GET method, you can access request headers via the
self.headers attribute and the request path via self.path. For example:
def do_GET(self):
response='http://%s/%s' % (self.headers['host'],
self.path)
I found a python http web server from http://www.linuxjournal.com/content/tech-tip-really-simple-http-server-python
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()
If the directory has a file named index.html, that file will be served as the initial file. If there is no index.html, then the files in the directory will be listed.
How do I modify the script so that I send a custom html to the browser?
As the name and documentation imply, SimpleHTTPServer is dead-simple, and intended to be used as sample code for building your own servers on top of the frameworks in the standard library.
So, if you want to do anything with it, you probably want to copy and modify the source, or just use it as inspiration.
And if you want to do anything serious, you probably want to use a framework made for writing real HTTP servers like tornado or twisted, or just use a stock HTTP server and delegate the dynamic pages to Python via, say, WSGI.
But if you really want to do this, you can. There's nothing stopping you from subclassing SimpleHTTPServer.SimpleHTTPRequestHandler and overriding its methods. For example:
class MyHandler(SimpleHTTPRequestHandler):
def send_head(self):
if self.translate_path(self.path).endswith('/foo'):
body = gaping_security_hole(self.path)
self.send_response(200)
self.send_header("Content-type", "text/html; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
return StringIO(body)
else:
return super(MyHandler, self).send_head()
Obviously you can check whatever you want there instead of endswith('/foo'). For example, as you can see from the source, the default implementation checks os.path.isdir, and if it's true checks whether it endswith('/'), and whether the directory has anything named index.html or index.htm, before deciding what to do.