Send text "http" over python socket - python

I am trying to create a HTTP server using python. The thing is I am getting everything to work except for sending a response message; if the message has a text http, the send() doesn't work.
Here is the snippet of the code:
connectionSocket.send('HTTP/1.1 200 OK text/html')
Here are the others I tried:
connectionSocket.send(''.join('%s 200 OK text/html' % ('HTTP/1.1')))
connectionSocket.send('%s 200 OK text/html' % ('HTTP/1.1'))
msg = 'HTTP/1.1 200 OK text/html'
for i in range(0, len(msg))
connectionSocket.send(msg[i])
The only thing that seems to work is entity-fying the any of the character in HTTP, like
connectionSocket.send('HTTP/1.1 200 OK text/html')
Where H is equivalent to H. Otherwise the browser doesn't display the header received from the python server socket.
The problem also goes when I am trying to send a 404 Message down the socket. The other contents are displayed, however, like a html file sent through the socket.
I want to know is there a proper way to do it? Because, if the client is not a browser, the html entity will not be understood.
Thanks in advance
Update:
Code:
from socket import *
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serverSocket.bind(('127.0.0.1', 1240))
serverSocket.listen(1);
while True:
print 'Ready to serve...'
connectionSocket, addr = serverSocket.accept()
try:
message = connectionSocket.recv(1024)
filename = message.split()[1]
f = open(filename[1:])
outputdata = f.read()
#Send one HTTP header line into socket
connectionSocket.send('HTTP/1.1 200 OK text/html') ## this is not working
#Send the content of the requested file to the client
for i in range(0, len(outputdata)):
connectionSocket.send(outputdata[i])
connectionSocket.close()
except IOError:
connectionSocket.send('HTTP/1.1 404 File not found') ## this is not working
connectionSocket.close();
serverSocket.close()
Screenshots:
Text as 'HTTP/1.1 ...'
Text as 'HTTP/1.1 ...'
HTML Code of hello.html
<html>
<head>
<title>Test Python</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>

You are not returning a correctly formed HTTP response. Your line
connectionSocket.send('HTTP/1.1 200 OK text/html') ## this is not working
is not even terminated by a newline, then immediately followed by the content of your file. Protocols like HTTP specify fairly rigorously what must be sent, and I find it little short of miraculous that you saw anything at all in your browser.
Try something like:
connectionSocket.send('HTTP/1.1 200 OK\nContent-Type: text/html\n\n')
This is the start of a correctly-formed HTTP 1.1 response with a primary response line and a single header. The double newline terminates the headers, preparing the client to read the content that follows.
http://www.jmarshall.com/easy/http/ is one of many approachable ways to learn a bit more about the protocol you have chosen to use. Good luck!

I'm not sure what connectionSocket you are using (which module, library, etc.) but if this thing is already part of a HTTP-related routine, it might well be that it already sends the necessary HTTP line without your doing. Yours then might disturb the process.
The quoted version (HTTP...) probably is not recognized by the HTTP protocol in the browser (I think that quoting is only recognized and interpreted in higher layers of the OSI stack) and therefore does not have the same effect.

Related

.recv function Socket programming TCP Server in Python

Im having trouble getting my very basic and simple TCP Server to properly work with http requests. This is what I have so far
from socket import *
import sys
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', 4567))
serverSocket.listen(1)
while True:
print('Ready to serve...')
connectionSocket, addr = serverSocket.accept()
print("connected from: ", addr)
try:
message = connectionSocket.recv(1024)
filename = message.split()[1]
f = open(filename[1:])
outputdata = f.read()
connectionSocket.send("HTTP/1.1 200 OK\r\n")
for i in range(0, len(outputdata)):
connectionSocket.send(outputdata[i].encode())
connectionSocket.send("\r\n".encode())
connectionSocket.close()
except IOError:
connectionSocket.send("file not found")
serverSocket.close()
sys.exit()
The error comes from the open statement. I dont fully understand how this line of code's return value is organized.
message = connectionSocket.recv(1024)
I know that the return value is in bytes but when I try to use a fuction to turn it into a string like decode() i get errors as well
I have the .py file and the html file sitting in the same directory on my local machine and the way I test this is I just run this and open up a browser and type in
http://127.0.0.1:4567/helloworld.html
My code then promptly crashes after receiving the HTTP request.
Any and all help will be greatly appreciated!
There are numerous problems with your code and since you don't state what specific issues you are concerned about, here is what I see:
connectionSocket.send(outputdata[i].encode())
connectionSocket.send("\r\n".encode())
That appears to send a newline after every character you send back to the client.
Also, it doesn't deal with the client disconnecting because you're sending back invalid data.
Even if what you were trying to do didn't have these errors in it, you don't appear to be attempting to send back a valid http response.
https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html

how to send http response message code:400 in python

I have written a web server in python and I want to send HTTP response message codes:400 instead of the response "Website Coming Soon!" on any client-request, please tell how can I do this.
The Server Code is:
import socket
import re
HOST = "localhost"
PORT = 13555
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(1)
print ("Serving HTTP on port %s ..." % PORT)
while True:
client_connection, client_address = listen_socket.accept()
request = client_connection.recv(2048)
response = "Website Coming Soon!" #this response should be http response message code:400
http_response = "HTTP/1.1 200 OK\n"+"Content-Type: text/html\n"+"\n"+"<html><body>"+response+"</body></html>\n"
client_connection.sendall(http_response)
client_connection.close()
Try to get to know the protocol you're trying to speak :)
HTTP is fairly simple, all HTTP messages consist of 3 basic parts, of which the 3rd is optional:
The request or status line (first line)
The request headers, each on one line (or with some escaping spread over multiple), followed by an extra newline
The request body, which is optional for most requests, and for some responses.
What you want to do is change the "status line" in a response message. Since you want to send the 400 status code, the first line in your response should be
HTTP/1.1 400 Bad request
But there's two things wrong here:
You don't actually parse the request, so you can't really tell the client he's doing something wrong (all 4xx codes represent client errors)
Your sending the wrong message. Probably, what you want is something like 503 Service unavailable
Dive into the specs. They're really, really straight forward. And if you read it thoroughly, and start speaking HTTP the way it is intended, the world gets another tiny bit better ;)

Python - Sending "Incomplete" GET requests

So I was reading about these partial GET requests that would make a server timeout the connection after a while on this request. How would send a partial GET request?..
import socket, sys
host = sys.argv[1]
request = "GET / HTTP/1.1\nHost: "+host+"\n\nUser-Agent:Mozilla 5.0\n" #How could I make this into a partial request?
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, 80))
s.sendto(request, (host, 80))
response = s.recv(1024)
How would I do this?
I think you confuse partial and incomplete requests:
partial: request for some part of a resource, that is a Range request like shown in the answer of falsetru. This will not cause a timeout but instead a response with code 206 and your requested part of the resource.
incomplete: your request is incomplete and cannot be processed by the server, thus it will wait for the rest of the request and timeout after a while if it does not get the request. In your question you already have such an incomplete request because you did not finish you request properly (it must end with \r\n\r\n and not a single \n). Other ways are just a TCP connect without sending any data or doing a POST request with a content-length and then not sending as much data as specified in the request header.
The HTTP headers ends too early. (\n\n should come after headers, before the contents)
import socket, sys
host = sys.argv[1]
request = "GET / HTTP/1.1\nHost: "+host+"\nUser-Agent:Mozilla 5.0\n\n"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, 80))
s.send(request)
response = s.recv(1024)
If you mean partial content retrieval, you can speicfy Range header:
"GET / HTTP/1.1\nHost: "+host+"\nUser-Agent:Mozilla 5.0\rRange: bytes=0-999\n\n"
NOTE
It should be \r\n not \n as line end, even if most (but not all) servers accept \n too.

A python socket client that outputs the source code of a website, why isn't this working?

The following code doesn't output anything(why?).
#!/usr/bin/python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("www.python.org" , 80))
print s.recv(4096)
s.close()
What do I have to change in order to output the source code of the python website as you would see when you go to view source in a browser?
HTTP is request/response protocol. You're not sending any request, thus you're not getting any response.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("www.python.org" , 80))
s.sendall("GET /\r\n") # you're missing this line
print s.recv(4096)
s.close()
Of course that will do the most raw HTTP/1.0 request, without handling HTTP errors, HTTP redirects, etc. I would not recommend it for actual usage beyond doing it as an exercise to familiarize yourself with socket programming and HTTP.
For HTTP Python provides few built in modules: httplib (bit lower level), urllib and urllib2 (high level ones).
You'll get a redirect (302) unless you use the full URL in your request.
Try this instead:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("www.python.org" , 80))
s.sendall("GET http://www.python.org HTTP/1.0\n\n")
print s.recv(4096)
s.close()
Of course if you just want the content of a URL this is far simpler. :)
print urllib2.urlopen('http://www.python.org').read()
I get the html with
def steal_html():
url='https://some_website.org'
with open('index.html', 'w') as FILE:
html = requests.get(url).text
FILE.write(html)

Socket receiving no data. Why?

I was learning socket programming and tried to design a basic http client of mine. But somehow everything is going good but I am not receiving any data. Can you please tell me what am I missing?
CODE
import socket
def create_socket():
return socket.socket( socket.AF_INET, socket.SOCK_STREAM )
def remove_socket(sock):
sock.close()
del sock
sock = create_socket()
print "Connecting"
sock.connect( ('en.wikipedia.org', 80) )
print "Sending Request"
print sock.sendall ('''GET /wiki/List_of_HTTP_header_fields HTTP/1.1
Host: en.wikipedia.org
Connection: close
User-Agent: Web-sniffer/1.0.37 (+http://web-sniffer.net/)
Accept-Encoding: gzip
Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7
Cache-Control: no-cache
Accept-Language: de,en;q=0.7,en-us;q=0.3
Referer: d_r_G_o_s
''')
print "Receving Reponse"
while True:
content = sock.recv(1024)
if content:
print content
else:
break
print "Completed"
OUTPUT
Connecting
Sending Request
298
Receving Reponse
Completed
While I was expecting it show me html content of homepage of wikipedia :'(
Also, it would be great if somebody can share some web resources / books where I can read in detail about python socket programming for HTTP Request Client
Thanks!
For a minimal HTTP client, you definitely shouldn't send Accept-Encoding: gzip -- the server will most likely reply with a gzipped response you won't be able to make much sense of by eye. :)
You aren't sending the final double \r\n (nor are you actually terminating your lines with \r\n as per the spec (unless you happen to develop on Windows with Windows line endings, but that's just luck and not programming per se).
Also, del sock there does not do what you think it does.
Anyway -- this works:
import socket
sock = socket.socket()
sock.connect(('en.wikipedia.org', 80))
for line in (
"GET /wiki/List_of_HTTP_header_fields HTTP/1.1",
"Host: en.wikipedia.org",
"Connection: close",
):
sock.send(line + "\r\n")
sock.send("\r\n")
while True:
content = sock.recv(1024)
if content:
print content
else:
break
EDIT: As for resources/books/reference -- for a reference HTTP client implementation, look at Python's very own httplib.py. :)

Categories