Im trying to write a simple Http proxy with python.
This is my code:
import BaseHTTPServer
import urllib2
import threading
HOST_NAME="localhost"
PORT_NUMBER=9090
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def handle_get_async(self):
opener = urllib2.build_opener()
#opener.addheaders = self.headers.items()
response = opener.open(self.path)
response_content=response.read()
response.close()
self.send_response(200)
self.send_header("Content-type",response.info().type)
self.end_headers()
self.wfile.write(response_content)
def handle_head_async(s):
s.send_responde(200)
s.send_Header("Content-type","text/html")
s.end_headers()
def do_HEAD(s):
thread = threading.Thread(target=self.handle_head_async)
thread.start()
thread.join()
def do_GET(self):
thread = threading.Thread(target=self.handle_get_async)
thread.start()
thread.join()
if __name__ == '__main__':
server_class = BaseHTTPServer.HTTPServer
httpd = server_class((HOST_NAME, PORT_NUMBER), RequestHandler)
httpd.serve_forever()
So everything works fine, but when I use opener.addheaders = self.headers.items() to copy the headers send by the browser and copy it to the new request I just recive just strange characters in the browser like this:
Ô½Yo#I¶&ø^¿ÂÓ«:¯”)JÜ—PJn’(q’ZCQ^Nw#ÝEßä)**€z`€æi€™—‹žy¨Ûfè—Æ4ptþ‰ê·ÂEãöüŒ9ÇÌÝé\œŠHeõB$Ý–sŽ}fvì˜Ùq³Ÿ¾«uªƒÛnS];þÍOøÅi¢1>âeÂsª|ÄD‰MsÂs’&:Îo˜ÂƒÃcb"ÊÇ?éÄ9Im‡¸G¼çŽEž;8þÉ‘lÕrGž!¹ªipĘžhž£ìˆ»ÃÀáŽO¦½3mNæTƒw¥÷ò‡#>?©£™jÈælß&žj“¦ø<ßý¸¶óþïêÆôï>ì w?Í!áñÈO?ÿøÇŸ‡;ðâ?…¢|äÅñÉR-"¸æ„ü¾|óðỔ:ñHEÎ[c~×G˜»ò»³®Ñq34aAÉ?8 °õ?8‰äHö~?vÙ$v"9–~O<{”Èø?S‡Ä
Has someone an idea whats the problem?
Related
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?
I wrote a webserver with SimpleHTTPRequestHandler and a small script to send a GET request with an argument to the server, to which the server responds with code 200.
What I want is for the script to close as soon as the server replies with 200 (which should happen when "self.send_response(200)" is ran, so I think the problem might be somewhere around there), instead of staying open until the called file, jg_server_ed.py, has finished.
Webserver code:
# server.py
import http.server
import socketserver
import subprocess
import webbrowser
from urllib.parse import urlparse
class Handler(http.server.SimpleHTTPRequestHandler):
def do_POST(self):
print(f"request body: {self.path}")
return
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
if self.path.startswith("/?sitename="):
try:
body_split = self.path.split("/?sitename=")
if body_split != "" or []:
print(f"Incoming request: {body_split[-1]}")
subprocess.call(f"python jg_server_ed.py {body_split[-1]}")
else: pass
except Exception as err: print(err)
else: pass
return super().do_GET()
if __name__ == "__main__":
print("Serving on port 8080, IP 0.0.0.0.")
socketserver.TCPServer(('0.0.0.0', 8080), Handler).serve_forever()
GET request sending script thingy:
# submit_to_server.py
import urllib3
http = urllib3.PoolManager()
url = input("URL: ")
print("Sending request...")
r = http.request('GET', f"http://server_ip_address/?sitename={url}")
if r.status == "200":
exit()
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()
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()
I'm just new in integrating ajax http request and return a python webserver http response. I really no have an idea how to use it.
For example my web page is on another IP . like 192.168.1.1 and i will get a data or a response from 192.168.1.2
then on my view:
function test(){
$.ajax({
url : "http://192.168.1.2:8012/",
type : "GET",
success : function(data) {
alert(data);
}
});
}
now on my python web server
import string,cgi,time
from os import curdir, sep
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import MySQLdb
from lxml import etree
from lxml.builder import E as buildE
import urllib
global db, cnn
db = MySQLdb.connect("localhost","root","password","schema" )
cnn = db.cursor()
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
global cnn, sql
self.wfile.write("Cannot GET "+self.path)
print "test"
self.send_response(200, "testing")
self.send_header('Content-type', 'xml')
self.end_headers()
self.wfile.write("testing")
def do_POST(self):
global rootnode
try:
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
if ctype == 'multipart/form-data':
query=cgi.parse_multipart(self.rfile, pdict)
self.send_response(301)
self.end_headers()
upfilecontent = query.get('upfile')
print "filecontent", upfilecontent[0]
self.wfile.write("<HTML>POST OK.<BR><BR>");
self.wfile.write(upfilecontent[0]);
except :
pass
def main():
try:
server = HTTPServer(('', 8012), MyHandler)
print 'started httpserver...'
server.serve_forever()
except KeyboardInterrupt:
print '^C received, shutting down server'
server.socket.close()
if __name__ == '__main__':
main()
I just want a returned data from the webserver. But i think im doing it wrong.
I think you shouldn't send data to self.wfile before sending ALL headers. And maybe you should send a 'Content-length' header to let your page know when it must stop waiting for data. Something like this:
data="Cannot GET "+self.path
self.send_response(200)
self.send_header('Content-type','text/xml')
self.send_header('Content-length',str(len(data))
self.end_headers()
self.wfile.write(data)