I'm trying out some PHP on my pc and made a little python server to host the files, one problem:
It can't do POST, I always get the error 501. I've heard that you can implement POST in these servers, but I didn't find how to do this, can someone help?
Here's my current server:
import http.server
import socketserver
PORT = 8080
Handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", PORT), Handler) as httpd:
print("serving at port", PORT)
httpd.serve_forever()
This is the script I personally use for when I need this kind of functionality:
#!/usr/env python3
import http.server
import os
import logging
try:
import http.server as server
except ImportError:
# Handle Python 2.x
import SimpleHTTPServer as server
class HTTPRequestHandler(server.SimpleHTTPRequestHandler):
"""
SimpleHTTPServer with added bonus of:
- handle PUT requests
- log headers in GET request
"""
def do_GET(self):
server.SimpleHTTPRequestHandler.do_GET(self)
logging.warning(self.headers)
def do_PUT(self):
"""Save a file following a HTTP PUT request"""
filename = os.path.basename(self.path)
# Don't overwrite files
if os.path.exists(filename):
self.send_response(409, 'Conflict')
self.end_headers()
reply_body = '"%s" already exists\n' % filename
self.wfile.write(reply_body.encode('utf-8'))
return
file_length = int(self.headers['Content-Length'])
with open(filename, 'wb') as output_file:
output_file.write(self.rfile.read(file_length))
self.send_response(201, 'Created')
self.end_headers()
reply_body = 'Saved "%s"\n' % filename
self.wfile.write(reply_body.encode('utf-8'))
if __name__ == '__main__':
server.test(HandlerClass=HTTPRequestHandler)
But perhaps a more fitting, and simpler script would be the following, as found on Flavio Copes' blog:
from http.server import BaseHTTPRequestHandler, HTTPServer
class handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
message = "Hello, World! Here is a GET response"
self.wfile.write(bytes(message, "utf8"))
def do_POST(self):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
message = "Hello, World! Here is a POST response"
self.wfile.write(bytes(message, "utf8"))
with HTTPServer(('', 8000), handler) as server:
server.serve_forever()
Related
I'm trying to create multithreaded web server in python, but it only responds to one request at a time and I can't figure out why. Can you help me, please?
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
from time import sleep
class ThreadingServer(ThreadingMixIn, HTTPServer):
pass
class RequestHandler(SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/plain')
sleep(5)
response = 'Slept for 5 seconds..'
self.send_header('Content-length', len(response))
self.end_headers()
self.wfile.write(response)
ThreadingServer(('', 8000), RequestHandler).serve_forever()
Check this post from Doug Hellmann's blog.
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from SocketServer import ThreadingMixIn
import threading
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
message = threading.currentThread().getName()
self.wfile.write(message)
self.wfile.write('\n')
return
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
"""Handle requests in a separate thread."""
if __name__ == '__main__':
server = ThreadedHTTPServer(('localhost', 8080), Handler)
print 'Starting server, use <Ctrl-C> to stop'
server.serve_forever()
I have developed a PIP Utility called ComplexHTTPServer that is a multi-threaded version of SimpleHTTPServer.
To install it, all you need to do is:
pip install ComplexHTTPServer
Using it is as simple as:
python -m ComplexHTTPServer [PORT]
(By default, the port is 8000.)
In python3, you can use the code below (https or http):
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
import threading
USE_HTTPS = True
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(b'Hello world\t' + threading.currentThread().getName().encode() + b'\t' + str(threading.active_count()).encode() + b'\n')
class ThreadingSimpleServer(ThreadingMixIn, HTTPServer):
pass
def run():
server = ThreadingSimpleServer(('0.0.0.0', 4444), Handler)
if USE_HTTPS:
import ssl
server.socket = ssl.wrap_socket(server.socket, keyfile='./key.pem', certfile='./cert.pem', server_side=True)
server.serve_forever()
if __name__ == '__main__':
run()
You will figure out this code will create a new thread to deal with every request.
Command below to generate self-sign certificate:
openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365
If you are using Flask, this blog is great.
It's amazing how many votes these solutions that break streaming are getting. If streaming might be needed down the road, then ThreadingMixIn and gunicorn are no good because they just collect up the response and write it as a unit at the end (which actually does nothing if your stream is infinite).
Your basic approach of combining BaseHTTPServer with threads is fine. But the default BaseHTTPServer settings re-bind a new socket on every listener, which won't work in Linux if all the listeners are on the same port. Change those settings before the serve_forever() call. (Just like you have to set self.daemon = True on a thread to stop ctrl-C from being disabled.)
The following example launches 100 handler threads on the same port, with each handler started through BaseHTTPServer.
import time, threading, socket, SocketServer, BaseHTTPServer
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
if self.path != '/':
self.send_error(404, "Object not found")
return
self.send_response(200)
self.send_header('Content-type', 'text/html; charset=utf-8')
self.end_headers()
# serve up an infinite stream
i = 0
while True:
self.wfile.write("%i " % i)
time.sleep(0.1)
i += 1
# Create ONE socket.
addr = ('', 8000)
sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(addr)
sock.listen(5)
# Launch 100 listener threads.
class Thread(threading.Thread):
def __init__(self, i):
threading.Thread.__init__(self)
self.i = i
self.daemon = True
self.start()
def run(self):
httpd = BaseHTTPServer.HTTPServer(addr, Handler, False)
# Prevent the HTTP server from re-binding every handler.
# https://stackoverflow.com/questions/46210672/
httpd.socket = sock
httpd.server_bind = self.server_close = lambda self: None
httpd.serve_forever()
[Thread(i) for i in range(100)]
time.sleep(9e9)
A multithreaded https server in python3.7
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
import threading
import ssl
hostName = "localhost"
serverPort = 8080
class MyServer(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(bytes("<html><head><title>https://pythonbasics.org</title></head>", "utf-8"))
self.wfile.write(bytes("<p>Request: %s</p>" % self.path, "utf-8"))
self.wfile.write(bytes("<p>Thread: %s</p>" % threading.currentThread().getName(), "utf-8"))
self.wfile.write(bytes("<p>Thread Count: %s</p>" % threading.active_count(), "utf-8"))
self.wfile.write(bytes("<body>", "utf-8"))
self.wfile.write(bytes("<p>This is an example web server.</p>", "utf-8"))
self.wfile.write(bytes("</body></html>", "utf-8"))
class ThreadingSimpleServer(ThreadingMixIn,HTTPServer):
pass
if __name__ == "__main__":
webServer = ThreadingSimpleServer((hostName, serverPort), MyServer)
webServer.socket = ssl.wrap_socket(webServer.socket, keyfile='./privkey.pem',certfile='./certificate.pem', server_side=True)
print("Server started http://%s:%s" % (hostName, serverPort))
try:
webServer.serve_forever()
except KeyboardInterrupt:
pass
webServer.server_close()
print("Server stopped.")
you can test it in a browser: https://localhost:8080
the running result is:
enter image description here
enter image description here
remind that you can generate your own keyfile and certificate use
$openssl req -newkey rsa:2048 -keyout privkey.pem -x509 -days 36500 -out certificate.pem
To learn details about creating self-signed certificate with openssl:https://www.devdungeon.com/content/creating-self-signed-ssl-certificates-openssl
I'm working on trying create a super basic python webserver based on BaseHTTPRequestHandler. When I perform the GET request to the address 127.0.0.1/a for the first time, everything works well and I recover an image on my browser.
However, when I repeat this GET request a second time, I do not get anything. Tracing the code, I can see that the code itself is running through the entire do_GET(self) segment.
I'm really confused as to why the webserver would work the first time and not the next.
Any and all help is much appreciated.
from http.server import BaseHTTPRequestHandler, HTTPServer
from os import curdir, sep
imagefile = "a.jpg"
imagepage =open(curdir+sep+imagefile, 'rb')
notfound = "File not found"
class webserverHandler(BaseHTTPRequestHandler):
def do_OPTIONS(self):
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header("Access-Control-Allow-Headers", "X-Requested-With")
def do_GET(self):
if self.path == "/a":
print("getting thg jpg file")
self.send_response(200)
self.send_header("Content-type","image/png")
self.end_headers()
self.wfile.write(imagepage.read())
else:
self.send_error(404, notfound)
def main():
try:
port = 1234
server = HTTPServer(('127.0.0.1', port), webserverHandler)
print("Web server is running on port {}".format(port))
server.serve_forever()
except KeyboardInterrupt:
print("^C entered, stopping web server...")
finally:
if server:
print("closing server")
server.socket.close()
if __name__ == '__main__':
main()
Thank you!
def do_GET(self):
notfound = "File not found"
if self.path == "/a":
print("getting thg jpg file")
self.send_response(200)
self.send_header("Content-type","image/png")
self.end_headers()
imagefile = "fig1.png"
imagepage =open(curdir+sep+imagefile, 'rb')
self.wfile.write(imagepage.read())
else:
self.send_error(404, notfound)
Please read file in each request.
Why:
imagepage.read() make file seek to end of the image file, So, we cannot read any data with next imagepage.read() from second request.
Or
We can use imageContent = imagepage.read() at first,
and we can send imageContent every request
from http.server import BaseHTTPRequestHandler, HTTPServer
from os import curdir, sep
imagefile = "fig1.png"
imagepage =open(curdir+sep+imagefile, 'rb')
imageContent = imagepage.read() # Read Image here
notfound = "File not found"
class webserverHandler(BaseHTTPRequestHandler):
def do_OPTIONS(self):
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header("Access-Control-Allow-Headers", "X-Requested-With")
def do_GET(self):
if self.path == "/a":
print("getting thg jpg file")
self.send_response(200)
self.send_header("Content-type","image/png")
self.end_headers()
self.wfile.write(imageContent)
else:
self.send_error(404, notfound)
def main():
try:
port = 1234
server = HTTPServer(('127.0.0.1', port), webserverHandler)
print("Web server is running on port {}".format(port))
server.serve_forever()
except KeyboardInterrupt:
print("^C entered, stopping web server...")
finally:
if server:
print("closing server")
server.socket.close()
if __name__ == '__main__':
main()
After a lot of trouble to make a ros and a python based http server work, I have another problem to combine two different codes.
Here is what I have written so far to write a code that publish ros topics yet it respond to http server at the same time. The problem is that server is OK unless I replace
httpd.serve_forever()
with
httpd.service_actions
to make it non-blocking. Then the server does not respond. Any way to resolve this problem yet keeping the code non-blcoking?
#!/usr/bin/env python3
import rospy
from std_msgs.msg import String
from http.server import BaseHTTPRequestHandler, HTTPServer
class S(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
self._set_headers()
self.wfile.write(b"<html><body><h1>hi!</h1></body></html>")
def do_HEAD(self):
self._set_headers()
def do_POST(self):
# Doesn't do anything with posted data
self._set_headers()
self.wfile.write(b"<html><body><h1>POST!</h1></body></html>")
def http_server_init(port,server_class=HTTPServer, handler_class=S):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
print('Starting httpd...')
return (httpd)
def http_server_loop(httpd):
#httpd.serve_forever()
httpd.service_actions()
def talker_init():
pub = rospy.Publisher('chatter', String, queue_size=10)
rospy.init_node('talker', anonymous=True)
rate = rospy.Rate(10) # 10hz
return (pub,rospy,rate)
def talker_loop(pub,rospy,rate):
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
if __name__ == '__main__':
from sys import argv
if len(argv) == 2:
http_port=int(argv[1])
else:
http_port=8080
httpd=http_server_init(http_port)
try:
pub,rospy,rate=talker_init()
while not rospy.is_shutdown():
http_server_loop(httpd)
talker_loop(pub,rospy,rate)
except rospy.ROSInterruptException:
pass
By the way, in ROS, this code should be called via
rosrun <packagename> <script>.py
Calling from bash leads to an error. Unless you remove the ROS-related codes.
I'm fairly new to coding in python. I created a local web server that says "Hello World" and displays the current time.
Is there a way to create a path, without creating a file, on the server program so that when I type in "/time" after 127.0.0.1 in the browser bar, it will display the current time? Likewise if I type "/date" it will give me the current date.
This is what I have so far:
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
import datetime
port = 80
class myHandler(BaseHTTPRequestHandler):
#Handler for the GET requests
def do_GET(self):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
# Send the html message
self.wfile.write("<b> Hello World !</b>"
+ "<br><br>Current time and date: " + str(datetime.datetime.now()))
server = HTTPServer(('', port), myHandler)
print 'Started httpserver on port ', port
#Wait forever for incoming http requests
server.serve_forever()
Very simple URL handler:
def do_GET(self):
if self.path == '/time':
do_time(self)
elif self.path == '/date':
do_date(self)
def do_time(self):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
# Send the html message
self.wfile.write("<b> Hello World !</b>"
+ "<br><br>Current time: " + str(datetime.datetime.now()))
I am writing a simple http server as part of my project. Below is a skeleton of my script:
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
class MyHanlder(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write('<html><body><p>OK</p></body></html>')
httpd = HTTPServer(('', 8001), MyHanlder)
httpd.serve_forever()
My question: how do I suppress the stderr log output my script produces every time a client connects to my server?
I have looked at the HTTPServer class up to its parent, but was unable to find any flag or function call to achieve this. I also looked at the BaseHTTPRequestHandler class, but could not find a clue. I am sure there must be a way. If you do, please share with me and others; I appreciate your effort.
This will probably do it:
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write('<html><body><p>OK</p></body></html>')
def log_message(self, format, *args):
return
httpd = HTTPServer(('', 8001), MyHandler)
httpd.serve_forever()