I'm trying to set up a HTTP server in a Python script. So far I got the server it self to work, with a code similar to the below, from here.
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
print("Just received a GET request")
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write('Hello world')
return
def log_request(self, code=None, size=None):
print('Request')
def log_message(self, format, *args):
print('Message')
if __name__ == "__main__":
try:
server = HTTPServer(('localhost', 80), MyHandler)
print('Started http server')
server.serve_forever()
except KeyboardInterrupt:
print('^C received, shutting down server')
server.socket.close()
However, I need to get variables from the GET request, so if server.py?var1=hi is requested, I need the Python code to put var1 into a Python variable and process it (like print it). How would I go about this? Might be a simple question to you Python pros, but this Python beginner doesn't know what to do! Thanks in advance!
Import urlparse and do:
def do_GET(self):
qs = {}
path = self.path
if '?' in path:
path, tmp = path.split('?', 1)
qs = urlparse.parse_qs(tmp)
print path, qs
urlparse.parse_qs()
print urlparse.parse_qs(os.environ['QUERY_STRING'])
Or if you care about order or duplicates, urlparse.parse_qsl().
Import in Python 3: from urllib.parse import urlparse
Related
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()
I can't figure out how to make this small http server reply the get request and play a sound in parallel.
Current code, does not close the get request until the sound "winsound.PlaySound("SystemExit", winsound.SND_ALIAS)" end playing.
What i need is for the sound to be async to the request so that the get request ends asap and the sound keeps playing.
#!/usr/bin/env python3
from http.server import HTTPServer, SimpleHTTPRequestHandler, test
import socketserver
from urllib.parse import urlparse
from urllib.parse import parse_qs
import sys
import winsound
class MyHttpRequestHandler(SimpleHTTPRequestHandler):
try:
def do_GET(self):
# Sending an '200 OK' response
self.send_response(200)
# Setting the header
self.send_header("Content-type", "text/html")
# Whenever using 'send_header', you also have to call 'end_headers'
self.end_headers()
html = "ok"
# Writing the HTML contents with UTF-8
self.wfile.write(bytes(html, "utf8"))
winsound.PlaySound("SystemExit", winsound.SND_ALIAS)
return
except Exception as e:
print(str(e))
# 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()
Use a flag to run it async:
winsound.PlaySound("SystemExit", winsound.SND_ALIAS|winsound.SND_ASYNC)
If you wish to have tighter control, use concurrent.futures.ThreadPoolExecutor() to run it in a different thread:
from concurrent.futures import ThreadPoolExecutor
import winsound
pool = ThreadPoolExecutor()
class MyHttpRequestHandler(SimpleHTTPRequestHandler):
try:
def do_GET(self):
# Sending an '200 OK' response
self.send_response(200)
# Setting the header
self.send_header("Content-type", "text/html")
# Whenever using 'send_header', you also have to call 'end_headers'
self.end_headers()
html = "ok"
# Writing the HTML contents with UTF-8
self.wfile.write(bytes(html, "utf8"))
pool.submit(winsound.PlaySound, "SystemExit", winsound.SND_ALIAS)
return
except Exception as e:
print(str(e))
BACKGROUND
So basically, it's question about execution scope in Python. Back to your code above, in order for request to finish it has to be execute all task.
send response (this one doesn't make effect, because you have to return result from the method get)
setting headers
playing music
Obviously, you return at the end of the request execution and your thread monitor just one. So request will finish after finishing all the tasks.
SOLUTION
So as you mentioned in the question, you are right. To play music on your Server on the request, you have to run async task and let you request return result from get request. For ex. by using asyncio (it's very handy lib, so check it out)
import asyncio
import socketserver
from http.server import SimpleHTTPRequestHandler
import winsound
class MyHttpRequestHandler(SimpleHTTPRequestHandler):
try:
def do_GET(self):
self.send_response(200)
self.wfile.write(bytes("Ok", "utf8"))
# Shared Queue of Background Tasks
asyncio.get_event_loop().run_until_complete(
MyHttpRequestHandler.play_music()
)
except Exception as e:
print(str(e))
#staticmethod
async def play_music():
try:
print('Playing sound!')
winsound.PlaySound("SystemExit", winsound.SND_ALIAS)
# Maybe you want to add Error handling
finally:
pass
# Create an object of the above class
handler = MyHttpRequestHandler
server = socketserver.TCPServer(
("", 8000), handler)
# Star the server
server.serve_forever()
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 am trying to serve a basic webpage in python.
If I cd to the dir and then run "python -m http.server 80" The page is displayed without issues, all formatting is correct. The issue is that I require some degree of security, so I have written a basic authentication python script which i run from the same directory. Unfortunately I get a badly rendered page with no formatting. Can anybody help me? All i need do is once fully authenticated, launch this web site in current directory.
Code is :-
import http.server
import socketserver
from http.server import BaseHTTPRequestHandler, HTTPServer
class CustomHandler(BaseHTTPRequestHandler):
''' Main class to present webpages and authentication. '''
def do_HEAD(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
print ('all authenticated')
self.end_headers()
def do_AUTHHEAD(self):
self.send_response(401)
self.send_header('WWW-Authenticate', 'Basic realm=\"SmarterADM\"')
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
''' Present frontpage with user authentication. '''
if self.headers['Authorization'] == None:
self.do_AUTHHEAD()
self.wfile.write(bytes('no auth header received', 'UTF-8'))
pass
elif self.headers['Authorization'] == 'Basic c21hcnRlcmFkbTpwYXNzdzByZA==':
self.do_HEAD()
self.wfile.write(bytes(self.headers['Authorization'], 'UTF-8'))
self.wfile.write(bytes(' authenticated!', 'UTF-8'))
rootdir = 'c:/Team/main/START/index.html' #file location
f = open(rootdir,'rb') #open requested file
self.wfile.write(f.read())
return render.rootdir
pass
else:
self.do_AUTHHEAD()
self.wfile.write(bytes(self.headers['Authorization'], 'UTF-8'))
self.wfile.write(bytes(' not authenticated Mark says NO!', 'UTF-8'))
pass
httpd = HTTPServer(('', 80), CustomHandler)
print ('started httpd...')
httpd.serve_forever()
if __name__ == '__main__':
main()
'''' rootdir = 'c:/RTS_Team/STAR2/STAR2/index.html' #file location
f = open(rootdir,'rb') #open requested file
self.wfile.write(f.read())
f.close() '''