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()
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 wrote the following code to accept a HTTP POST and then write out a temp file that includes the POST data and then send that temp file to a printer using subprocess and the UNIX lp command.
from http.server import HTTPServer, BaseHTTPRequestHandler
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)
try:
result = json.loads(body, encoding='utf-8')
# Do other stuff with result
p = subprocess.Popen(['/usr/bin/env', 'lp', '-d', printer_queue, temp.name], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
self.send_response(200)
self.end_headers()
response = BytesIO()
response.write(b'POST Received: ')
response.write(body)
self.wfile.write(response.getvalue())
except Exception as err:
tb = traceback.format_exc()
print(tb)
self.send_response(500) # 500 Internal Server Error
self.end_headers()
response = BytesIO()
response.write(b'ERROR: Blah')
self.wfile.write(response.getvalue())
httpd = HTTPServer(('localhost', 8000), SimpleHTTPRequestHandler)
and everything was awesome. Then I read that HTTPServer shouldn't be used in Production and everything was no longer awesome.
So how can I write the equivalent code that can be used as a production server? I have a Apache web server, but I'm not sure how to add the above Python code to it (preferrably without changing the above code too much since there is a lot of it).
I found out a way to connect your code with nginx server. At first add some code with your function add create socket and after that write a nginx conf file. it will work
Step 1 :
add main() function in your function
from http.server import HTTPServer, BaseHTTPRequestHandler
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)
try:
result = json.loads(body, encoding='utf-8')
# Do other stuff with result
p = subprocess.Popen(['/usr/bin/env', 'lp', '-d', printer_queue, temp.name], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
self.send_response(200)
self.end_headers()
response = BytesIO()
response.write(b'POST Received: ')
response.write(body)
self.wfile.write(response.getvalue())
except Exception as err:
tb = traceback.format_exc()
print(tb)
self.send_response(500) # 500 Internal Server Error
self.end_headers()
response = BytesIO()
response.write(b'ERROR: Blah')
self.wfile.write(response.getvalue())
def main():
try:
server = HTTPServer(('localhost', 8000), SimpleHTTPRequestHandler)
print ('Starting BaseServer.')
server.serve_forever ()
except KeyboardInterrupt:
print ('Interrupt recieved; closing server socket')
server.socket.close()
if __name__ == '__main__':
main()
Step 2 :
nginx.conf file should be like this
server {
location / {
root /data/www;
}
location / {
proxy_pass http://localhost:8000;
}
}
If face any issue comment below
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() '''
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