Use variable on Http-Server - python

I am using 'some_var' on my Http-Server. It contains some state of my application. It can be changed by requests from '/some_url'.
from http.server import HTTPServer, SimpleHTTPRequestHandler
from urllib.parse import urlparse
import json
class RequestHandler(SimpleHTTPRequestHandler):
def _send_headers(self, code=200, content_type='text/html'):
self.send_response(code)
self.send_header('Content-type', content_type)
self.end_headers()
def do_GET(self):
self._send_headers()
SimpleHTTPRequestHandler.do_GET(self)
def do_POST(self):
self._send_headers()
path = urlparse(self.path).path
length = int(self.headers.get('content-length'))
data = self.rfile.read(length)
if path.startswith('/some_url'):
self.some_function(data)
def some_function(self, data):
jsondata = data.decode()
data = json.loads(jsondata)
self.server.some_var = data['some_data']
if __name__ == '__main__':
httpd = HTTPServer(('', 8080), RequestHandler)
httpd.some_var = 0
httpd.serve_forever()
Program is working.
The problem is: The Linter in my editor complains that 'some_var' is unknown.
Is there a cleaner way to add variables to the server?
Or do I have to use a something like a database for this?

Related

Web server in python in plainText

I am looking for a way to expose a text file with Python web server.
I get some python code to run a web server :
import http.server
import socketserver
port = 9500
address = ("", port)
handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(address, handler)
print(f"Serveur démarré sur le PORT {port}")
httpd.serve_forever()
It's working fine. but i would :
Run a web sever exposing textplain content (and not Html content).
Set manually the workpath and name of index file (default: index.html)
keep Python server Code simple and light
I found some help on the web :
handler.extensions_map['Content-type'] = 'text/plain'
or
handler.send_header('Content-Type','text/plain')
But none os this proposition work.
Could you help me to build a simple python code to do this ?
Thanks a lot,
Script for Python 2 with using only built-in modules, just place the absolute path of the file which you want to be served <INSERT_FILE>:
#!/usr/bin/python
from SimpleHTTPServer import SimpleHTTPRequestHandler
import BaseHTTPServer
from io import StringIO
import sys
import os
class MyHandler(SimpleHTTPRequestHandler):
def send_head(self):
# Place here the absolute path of the file
with open("<INSERT_FILE>", "r") as f:
body = unicode("".join( f.readlines()))
self.send_response(200)
self.send_header("Content-type", "text/html; charset=UTF-8")
self.send_header("Content-Length", str(len(body)))
#self.send_header("Server", "SimpleHTTP/1.1 Python/2.7.5")
self.end_headers()
# text I/O binary, and raw I/O binary
# initial value must be unicode or None
return StringIO(body)
if __name__ == "__main__":
HandlerClass = MyHandler
ServerClass = BaseHTTPServer.HTTPServer
Protocol = "HTTP/1.1"
server_address = ('', 5555)
HandlerClass.protocol_version = Protocol
httpd = ServerClass (server_address, HandlerClass)
print("serving on port 5555")
httpd.serve_forever()
For python3 (SimpleHTTPServer module has been merged into http.server), place absolute path <INSERT_FILE>:
from http.server import HTTPServer, BaseHTTPRequestHandler
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
# place absolute path here
f_served = open('<INSERT_FILE>','rb')
f_content = f_served.read()
f_served.close()
self.wfile.write(f_content)
if __name__ == "__main__":
httpd = HTTPServer(('localhost', 5555), SimpleHTTPRequestHandler)
httpd.serve_forever()
I recommend using aiohttp with its lowlevel server, which is described here:
You can either return plain text, or you change the content type of your web.Response to text/html to send data that will be interpreted as html.
You can just replace the "OK" in the text="OK" with whatever plain text you wish. Or you replace it with the content of your *.html and change the content_type.
import asyncio
from aiohttp import web
async def handler(request):
return web.Response(text="OK")
async def main():
server = web.Server(handler)
runner = web.ServerRunner(server)
await runner.setup()
site = web.TCPSite(runner, 'localhost', 8080)
await site.start()
print("======= Serving on http://127.0.0.1:8080/ ======")
# pause here for very long time by serving HTTP requests and
# waiting for keyboard interruption
await asyncio.sleep(100*3600)
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(main())
except KeyboardInterrupt:
pass
loop.close()

How to visualize the body part of a BaseHTTPRequestHandler

I'm writing a server in Python and I want to send some data in the body part of a GET request. Currently when I run my code it just freezes.
I tried to put it in a try/except and read details about the instance variable rfile but I didn't find anything helpful
Client-side :
import http.client
import sys
import os
#get http server ip
http_server = sys.argv[1]
#create a connection
conn = http.client.HTTPConnection(http_server)
while 1:
cmd = input('input command (ex. GET index.html): ')
cmd = cmd.split()
f = open('data.txt')
if cmd[0] == 'exit': #tipe exit to end it
break
#request command to server
conn.request(cmd[0],'',f.read())
#get response from server
rsp = conn.getresponse()
#print server response and data
print(rsp.status, rsp.reason)
data_received = rsp.read()
print(data_received)
Server-side :
from http.server import BaseHTTPRequestHandler,HTTPServer
import os
class TestHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
a = ''
fichier = open("data2.txt", "w")
try:
fichier.write(self.rfile.read())
except:
self.send_response(200)
self.send_header('Content-type','text-html')
self.end_headers()
return
def run():
print('http server is starting...')
server_address = ('127.0.0.1',80)
httpd = HTTPServer(server_address, PancakeHTTPRequestHandler)
print('htttp server is running...')
httpd.serve_forever()
if __name__ == '__main__':
run()
I expect being able to write my data from my GET request in my data2.txt file.
Thank you for your help
It freezes because of the self.rfile.read() in your server.py. The read method expect either EOF or a byte length to read. See https://docs.python.org/3/library/io.html#io.BufferedIOBase.read
You're trying to log the client requests made to the server, a quick work around would be to pass the content length of the request to the read method with int(self.headers.get('Content-Length'))
In the end it gives us:
client.py
import http.client
import sys
import os
#get http server ip
http_server = sys.argv[1]
#create a connection
conn = http.client.HTTPConnection(http_server)
while 1:
cmd = input('input command (ex. GET index.html): ')
cmd = cmd.split()
f = open('data.txt')
if cmd[0] == 'exit': #tipe exit to end it
break
#request command to server
conn.request(cmd[0], '', f.read())
#get response from server
rsp = conn.getresponse()
#print server response and data
print(rsp.status, rsp.reason)
data_received = rsp.read()
print(data_received)
server.py
from http.server import BaseHTTPRequestHandler,HTTPServer
import os
class TestHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
a = ''
fichier = open("data2.txt", "a")
try:
content_length = int(self.headers.get('Content-Length'))
response_str = self.rfile.read(content_length)
fichier.write(response_str.decode('utf-8'))
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
except:
self.send_response(200)
self.send_header('Content-type','text-html')
self.end_headers()
fichier.close()
return
def run():
print('http server is starting...')
server_address = ('127.0.0.1',80)
httpd = HTTPServer(server_address, TestHTTPRequestHandler)
print('htttp server is running...')
httpd.serve_forever()
if __name__ == '__main__':
run()
ps. I don't know what PancakeHTTPRequestHandler was so I replaced it with TestHTTPRequestHandler. And I also added a response in try except on the server side so that the the client gets a response otherwise it will crash.

Mock HTTP server that performs content negotiation

I normally use Python's http.server to mock an HTTP server but this time I need the server to perform content negotiation.
I just need it to return an error if it cannot match the Accept header. Python's server ignores the header.
The way to run the server could be in a thread or in a separate process such as by running python -m http.server.
You can, still using http.server, but using a custom handler...
class MockHandler(http.server.BaseHTTPRequestHandler):
protocol_version = 'HTTP/1.1'
def do_GET(self):
if 'text/html' not in self.headers['Accept']:
self.send_response(406)
else:
self.send_response(200)
self.end_headers()
self.wfile.write(b'some data')
class ThreadedHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
pass
server_address = ('localhost', 8888)
server = ThreadedHTTPServer(server_address, MockHandler)
server.daemon_threads = True
thread = threading.Thread(target=server.serve_forever)
thread.daemon = True
thread.start()
(Note: it's a HTTP 1.1 server, since most servers are these days, and it's thread/multiple request-safe, but you can probably simplify if you would like...)
A full example in a small test-suite-of-one along with an example "production" function that you might want to test is below.
import http.server
import socketserver
import threading
import unittest
import urllib.request
def example_production_function(accept_header):
req = urllib.request.Request('http://localhost:8888', headers={'Accept': accept_header});
try:
urllib.request.urlopen(req)
return 'Allowed'
except urllib.error.HTTPError as e:
return 'Not allowed'
class TestServer(unittest.TestCase):
def test(self):
class MockHandler(http.server.BaseHTTPRequestHandler):
protocol_version = 'HTTP/1.1'
def do_GET(self):
if 'text/html' not in self.headers['Accept']:
self.send_response(406)
else:
self.send_response(200)
self.end_headers()
self.wfile.write(b'some data')
class ThreadedHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
pass
server_address = ('localhost', 8888)
server = ThreadedHTTPServer(server_address, MockHandler)
server.daemon_threads = True
thread = threading.Thread(target=server.serve_forever)
thread.daemon = True
thread.start()
result = example_production_function('text/html')
self.assertEqual(result, 'Allowed')
result = example_production_function('application/json')
self.assertEqual(result, 'Not allowed')
server.shutdown()
server.server_close()
if __name__ == '__main__':
unittest.main()

Build a Simple HTTPServer inside Docker image with Python

I have a docker image running, but I have no access to management since they are given to us by an administrator.
I want to run a simple HTTP-Server from a Python script. The script is the following:
import SimpleHTTPServer
import SocketServer as socketserver
import os
import threading
class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
path_to_image = 'RGBWebcam1.png'
img = open(path_to_image, 'rb')
statinfo = os.stat(path_to_image)
img_size = statinfo.st_size
print(img_size)
def do_HEAD(self):
self.send_response(200)
self.send_header("Content-type", "image/png")
self.send_header("Content-length", img_size)
self.end_headers()
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "image/png")
self.send_header("Content-length", img_size)
self.end_headers()
f = open(path_to_image, 'rb')
self.wfile.write(f.read())
f.close()
class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
def __init__(self, server_adress, RequestHandlerClass):
self.allow_reuse_address = True
socketserver.TCPServer.__init__(self, server_adress, RequestHandlerClass, False)
if __name__ == "__main__":
HOST, PORT = "172.17.0.2", 9999
server = MyServer((HOST, PORT), MyHandler)
server.server_bind()
server.server_activate()
server_thread = threading.Thread(target=server.serve_forever)
server_thread.start()
while(1):
print "test"
I looked up the IP-Adress with ifconfig however it is a different adress like the one I use when connecting to the Docker Image (it is a 141.19 ... address). So now if I try to reach the page it is not available on neither one of the adresses. Is there any way to route it to the 'real' IP-Address ?

Testing web server through linux terminal

I was just curious, how can I write a python test code so that I can test the GET/POST methods?
I am unable to figure out a way so that running the server and testing these methods can be done at the same time. Can someone help, thanks
from os import curdir
from os.path import join as pjoin
from http.server import BaseHTTPRequestHandler, HTTPServer
class StoreHandler(BaseHTTPRequestHandler):
store_path = pjoin(curdir, 'store.json')
def do_GET(self):
if self.path == '/store.json':
with open(self.store_path) as fh:
self.send_response(200)
self.send_header('Content-type', 'text/json')
self.end_headers()
self.wfile.write(fh.read().encode())
def do_POST(self):
if self.path == '/store.json':
length = self.headers['content-length']
data = self.rfile.read(int(length))
with open(self.store_path, 'w') as fh:
fh.write(data.decode())
self.send_response(200)
server = HTTPServer(('', 8080), StoreHandler)
server.serve_forever()
import requests
r = requests.get("http://127.0.0.1:8080/store.json")
print(r.status_code)
this will give back 200 as specified in your code

Categories

Resources