I am trying to write a basic "echo" HTTP server that writes back the raw data it receives in the request. How can I get the request data as a string?
This is my program:
#!/usr/bin/env python
from http.server import HTTPServer, BaseHTTPRequestHandler
class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
print('data', self.rfile.readall())
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
message = 'Hello Client!'
self.wfile.write(bytes(message, 'utf8'))
return
def server_start():
address = ('', 1992)
httpd = HTTPServer(address, RequestHandler)
httpd.serve_forever()
server_start()
Error:
self.rfile.readall(): '_io.BufferedReader' object has no attribute 'readall'
If it's a get request there won't be a body, so the data is going to be sent in the url.
from http.server import HTTPServer, BaseHTTPRequestHandler
import urlparse
class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
parsed_path = urlparse.urlparse(self.path)
print(parsed_path.query)
...
Otherwise, you should implement a POST method if you want to send any more complex object as data (take a look at different HTTP methods if you're not familiar with them).
A post method would be something like:
def do_POST(self):
post_body = self.rfile.readall()
Note that here you can use the method rfile.readall(). Here you have a nice gist with some examples!
Related
Hey so I have been trying to make a script that just reads the amount of followers someone has and then send the amount of followers back to the server that requested it. I have absolutely no idea how http works or how to properly format a variable to go across it. Whenever I make a request I get a bad response error. I know what is causing this, it’s the variable and how python formats it, but how would I send this over http? Any help? (Also this server won't have very much traffic at all)
import selenium
from selenium import webdriver
import time
import http
import http.server
import socketserver
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
driver = webdriver.Chrome()
class requestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('content-type', 'text/html')
self.end_headers
print(self.path[1:])
driver.get('https://www.tiktok.com/#%s?lang=en' % self.path[1:])
FOLLOWERS = driver.find_element_by_xpath('//*[#id="main"]/div[2]/div[2]/div/header/h2[1]/div[2]/strong').text
driver.close
print(str(FOLLOWERS))
self.wfile.write((str(FOLLOWERS).encode()))
def main():
PORT = 8000
server = HTTPServer(('', PORT), requestHandler)
print('Server running on port %s' % PORT)
server.serve_forever()
if __name__ == '__main__':
main()```
You forgot to create a function call when ending the header.
self.end_headers()
is what you want (the round brackets are missing). otherwise, chrome won't recognize this as a valid HTTP response.
Interestingly, this code works when using firefox.
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()
Im trying to create a simple HTTP server that will receive POST messages and provide a simple response. Im using the standard HTTPServer with python. The client connects using a session() which should use a persistent connection but after each POST I see the message below in the debug that the connection is dropping.
INFO:urllib3.connectionpool:Resetting dropped connection:
DEBUG:urllib3.connectionpool:"GET / HTTP/1.1" 200 None
The client works properly when I try it with Apache so I believe the issue is in my simple server configuration. How can I configure the simple http server to work with persistent connections?
Simple Server Python Code:
from http.server import HTTPServer, BaseHTTPRequestHandler
from io import BytesIO
import time
import datetime
import logging
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def _set_response(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.send_header("Connection", "keep-alive")
self.send_header("keep-alive", "timeout=5, max=30")
self.end_headers()
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)
curr_time = datetime.datetime.now()
data = ('{"msgid":"0x0002", "timestamp": "'+ str(curr_time) +'", "message":"Test http response from Raspberry Pi HTTP server"}').encode()
self.send_response(200)
self.end_headers()
response = BytesIO()
#response.write(b'This is POST request. ')
#response.write(b'Received: ')
response.write(data)
self.wfile.write(response.getvalue())
print("Simple HTTP Server running...")
logging.basicConfig(level=logging.DEBUG)
httpd = HTTPServer(('', 8000), SimpleHTTPRequestHandler)
httpd.serve_forever()
Client Python code:
#!/usr/bin/env python
# Using same TCP connection for all HTTP requests
import os
import json
import time
import datetime
import logging
import requests
from requests.auth import HTTPBasicAuth
logging.basicConfig(level=logging.DEBUG)
start_time = time.time()
def get_data(limit):
session = requests.Session()
url = "http://localhost:8000"
for i in range(10):
curr_time = datetime.datetime.now()
data = '{"msgid":"0x0001", "timestamp": "'+ str(curr_time) +'", "message":"Test http message from Raspberry Pi"}'
print("Sending Data: " + data)
response = session.post(url.format(limit), data)
#response_dict = json.loads(response.text)
print("Received Data: " + response.text)
if __name__ == "__main__":
limit = 1
get_data(limit)
print("--- %s seconds ---" % (time.time() - start_time))
You aren't actually setting the Connection header in your POST handler. In order for persistent connections to work, you'll also need to set the Content-Length header in the response so that client knows how many bytes of the HTTP body to read before reusing the connection.
Try this POST handler, adapted from your code:
def do_POST(self):
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
# Process the request here and generate the entire response
response_data = b'{"stuff": 1234}'
# Send the response
self.send_response(200)
self.send_header("Connection", "keep-alive")
self.send_header("Content-Length", str(len(response_data)))
self.end_headers()
# Write _exactly_ the number of bytes specified by the
# 'Content-Length' header
self.wfile.write(response_data)
I am trying to write a simple multithreaded http server which answers requests after 5 sec.
This code does not work, two simultaneous requests take 10 sec to complete, and I don't understand why.
from socketserver import ThreadingMixIn
from http.server import SimpleHTTPRequestHandler, HTTPServer, BaseHTTPRequestHandler
class ThreadingSimpleServer(ThreadingMixIn, HTTPServer):
pass
import sys
import os
import time
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
time.sleep(5)
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
self.wfile.write("answer")
return
server = ThreadingSimpleServer(('', 8000), Handler)
try:
while 1:
sys.stdout.flush()
server.handle_request()
except KeyboardInterrupt:
print("Finished")
You are calling handle_request, which handles one request after the other. You have to use serve_forever, so that the server can handle request automatically.
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()