I wrote a HTTP server using python, but I do not know how to get the HTTP body. what should I do to get the HTTP body?
here is my code:
from http.server import HTTPServer,BaseHTTPRequestHandler
class MyHTTPHandler(BaseHTTPRequestHandler):
def do_GET(self):
print("connect from ",self.client_address)
print(self.headers)
length = self.headers['Content-Length']
print(length)
addr = ('',21567)
server = HTTPServer(addr,MyHTTPHandler)
server.serve_forever()
Having a request body in a GET request is not a good practice, as its discussed here: HTTP GET with request body
Instead, you can change your method to POST and check there the BaseHTTPRequestHandler documentation: https://docs.python.org/2/library/basehttpserver.html
Especially this part:
rfile
Contains an input stream, positioned at the start of the optional input data.
Related
I need to connect/send msg to http://localhost:8001/path/to/my/service, but I am not able to find how to do that. I know how to send if I only have localhost and 8001, but I need this specific path /path/to/my/service. There is where my service is running.
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(<full-url-to-my-service>)
s.sendall(bytes('Message', 'utf-8'))
Update
My service is running on localhost:8001/api/v1/namespaces/my_namespace/services/my_service:http/proxy. How can I connect to it with python?
As #furas told in the comments
socket is primitive object and it doesn't have specialized method for this - and you have to on your own create message with correct data. You have to learn HTTP protocol and use it to send
This is a sample snippet to send a GET request in python using requests library
import requests
URL = 'http://localhost:8001/path/to/my/service'
response_text = requests.get(URL).text
print(response_text)
This assumes the Content-Type that GET URL produces is text. If it is json, then a minor change is required
import requests
URL = 'http://localhost:8001/path/to/my/service'
response_json = requests.get(URL).json()
print(response_json)
There are other ways to achieve the same using other good frameworks like urllib, and so on.
Here is the documentation of requests library for reference
sendall() requires bytes, so String must be encoded.
s.sendall("foobar".encode())
I'm running the code below to get POST messages. How do I get the file (sent with POST) and how do I respond with HTTP status code 200 OK?
#!/usr/bin/env python
import ssl
import BaseHTTPServer, SimpleHTTPServer
from BaseHTTPServer import BaseHTTPRequestHandler
class HttpHandler(BaseHTTPRequestHandler):
def do_POST(self):
print "got POST message"
# how do I get the file here?
print self.request.FILES
httpd = BaseHTTPServer.HTTPServer(('localhost', 4443), HttpHandler)
httpd.socket = ssl.wrap_socket(httpd.socket, certfile='./server.pem', server_side=True)
httpd.serve_forever()
$curl -X POST -d #../some.file https://localhost:4443/resource --insecure
AttributeError: 'SSLSocket' object has no attribute 'FILES'
BaseHTTPRequestHandler will process the first line and the headers of the http request then leave the rest up to you.
You need to read the remainder of the request using BaseHTTPRequestHandler.rfile
You can use self.send_response(200) to respond with 200 OK
Given the curl command you have specified the following should answer your question:
class HttpHandler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers['Content-Length'])
file_content = self.rfile.read(content_length)
# Do what you wish with file_content
print file_content
# Respond with 200 OK
self.send_response(200)
Note that by using -d #../some.file in your curl command you are saying "this is an ascii file, oh and strip out the newlines and carriage returns please", thus there could be differences between the file you are using and the data you get in the request. Your curl command does not emulate an html form file-upload like post request.
It is generally available in
request.FILES
dictionary
I have the following code for a simple BaseHTTPServer based server.
class myHandler(BaseHTTPRequestHandler):
#Handler for the GET requests
def do_GET(self):
# Parse the query_str
query_str = self.path.strip().lower()
if query_str.startswith("/download?"):
query_str = query_str[10:]
opts = urlparse.parse_qs(query_str)
# Send the html message and download file
self.protocol_version = 'HTTP/1.1'
self.send_response(200)
self.send_header("Content-type", 'text/html')
self.send_header("Content-length", 1)
self.end_headers()
self.wfile.write("0")
# Some code to do some processing
# ...
# -----------
self.wfile.write("1")
I was expecting the HTML page to show "1", but it shows "0". How can I update the response through keep alive?
I believe you are setting self.protocol_version to 'HTTP/1.1' too late. You are doing it in your do_GET() method, at which point your request handler has already been instantiated, and the server has already inspected that instance's protocol_version property.
Better to set it on the class:
class myHandler(BaseHTTPRequestHandler):
protocol_version = 'HTTP/1.1'
Not sure what you are trying to accomplish, but if you want the 1 to be sent, you need to set your content-length to 2 or remove it entirely. The 1 is not going to overwrite the 0, so you will see 01.
https://docs.python.org/2/library/basehttpserver.html
protocol_version
This specifies the HTTP protocol version used in responses. If set to 'HTTP/1.1', the server will permit HTTP persistent connections; however, your server must then include an accurate Content-Length header (using send_header()) in all of its responses to clients. For backwards compatibility, the setting defaults to 'HTTP/1.0'.
I faced same question. I tried set protocol_version in my do_METHOD() function which doesn't work.
My code look like this.
def _handle(self, method):
self.protocol_version = "HTTP/1.1"
# some code here
def do_GET(self):
self._handle("GET")
I used ss and tcpdump to detect network and finally find server will reset connection after send response although it use http/1.1.
So I try set protocol_version just under my class which inherited from standard library class and it works. Because of cost of time, I don't dive into source code. Hope it works for others.
There is some way to remove HTTP Header 'Server: TwistedWeb/13.1.0' from responses from a Twisted based web application?
You can rewrite any header by calling the request.setHeader method.
class RootPage(Resource):
def getChild(self, name, request):
request.setHeader('server', 'MyVeryOwnServer/1.0')
return OtherResource(name)
The change applies to any resources on your site; you could put it in your Site class. You want that 404 or 500 errors would also return correct header; so you should set it as earlier as possible but not before it is set by twisted itself (in order to overwrite it):
#!/usr/bin/env python
import sys
from twisted.web import server, resource
from twisted.internet import reactor
from twisted.python import log
class Site(server.Site):
def getResourceFor(self, request):
request.setHeader('server', 'Server/1.9E377')
return server.Site.getResourceFor(self, request)
# example from http://twistedmatrix.com/
class HelloResource(resource.Resource):
isLeaf = True
numberRequests = 0
def render_GET(self, request):
self.numberRequests += 1
request.setHeader("content-type", "text/plain")
return "I am request #" + str(self.numberRequests) + "\n"
log.startLogging(sys.stderr)
reactor.listenTCP(8080, Site(HelloResource()))
reactor.run()
Default Server http header is specified in t.w.server.version.
I know this is an old question, but if you would like to remove the server http header. I am talking about the
request.setHeader('Server', 'SomeServer')
This is set by Twisted Web automagically if you don't specify a value. You can remove it by using the inner Headers class. For example,
request.responseHeaders.removeHeader('Server')
This will remove the Server Http Header.
I am a newcomer to the Python and Twisted game so excuse the ignorance I will likely be asking this question with. As a sort of first program, I am trying to write a basic HTTP server using twisted.web.sever which would simply print to screen the HTTP request, and then print to screen the HTTP response. I am trying to print the entire message. Here is what I have so far:
from twisted.internet import reactor
from twisted.web.server import Site
from twisted.web.resource import Resource
import time
class TestPage(Resource):
isLeaf = True
def render_GET(self, request):
response = "Success"
print "You're request was %s" % request
print "The sever's response was %s" % response
return response
resource = TestPage()
factory = Site(resource)
reactor.listenTCP(8000, factory)
reactor.run()
So far, I am having success printing the request. What I want to know is where I can access the raw response data, not just the textual message. Also, if I wanted to start parsing the request/response for information, what would be the best way to go about doing that?
Edit: I'm also new to stackoverflow, how do I get this code to display properly?
Take a look at the Request and IRequest API docs to get an idea of what that request parameter offers you. You should be able to find just about everything in the request there.
I'm not sure what you mean by raw response data though. The response is up to you to generate.