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 ;)
Related
I have a server-side program in python that is expecting an image and is working fine when tested with a client-side program in python.
I want to send image to this server using flutter and I'm failing to do so..
Here's my server-side code
import socket #server
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # AF_INET = IP, SOCK_STREAM = TCP
server.bind(('localhost', 1112)) # 127.0.0.1
server.listen()
client_socket, client_address = server.accept()
file = open('2.jpg', "wb")
image_chunk = client_socket.recv(1024) # stream-based protocol
while image_chunk:
file.write(image_chunk)
image_chunk = client_socket.recv(1024)
file.close()
client_socket.close()
I have tried using dio, http and MultiPart
Here are snippets from my failed attempts:
MultiPart
var uri = Uri.parse('https://10.0.2.2:1112');
var request = MultipartRequest('POST', uri)
..files.add(await MultipartFile.fromPath(
'picture', filePath,
contentType: MediaType('application', 'jpeg')));
var response = await request.send();
if (response.statusCode == 200) print('Uploaded!');
Dio
Dio dio = new Dio();
FormData formData = new FormData.fromMap({
"file": await MultipartFile.fromPath(filePath, filename: basename(filePath),
contentType: MediaType('application', 'jpeg'),)
});
await dio.post('https://10.0.2.2:1112', data: formData);
I'm able to create a connection but I'm not able to send the file.
P.S: I have almost no experience of working with sockets, so I'm stuck at this.
The problem is that you are trying to connect to a socket api (not websocket these are different) via HTTP request and on server-side expecting to get image bytes but that's not gonna happen because as you know HTTP has it's own specification RFC2616. so what you will get there is some http headers and body.
Actually you can send http request to a socket but on the server-side you must do the heavy lifting. i mean reading http header line by line and then reading the Transfer-Encoding and Content-Length headers to know how to read the remaining bytes of the request, and then parsing the body data.
The Content-Length entity header indicates the size of the entity-body, in bytes, sent to the recipient.
The Transfer-Encoding header specifies the form of encoding used to safely transfer the payload body to the user.
The solution is either:
using dart socket library at the client side and then sending your image through socket instead of http request (this link might be helpful )
Or creating a RESTFUL API and send your image via http request like you did before.
hope i could help you:)
Since you are dealing with websocket, you have to checkout this package web_socket_channel.
You first need to make connection with your socket channel using
var channel = IOWebSocketChannel.connect(Uri.parse('ws://localhost:1234'));
To listen to changes from your websocket channel, you will use:
channel.stream.listen((message) {
print("NEW MESSAGE");
});
To send data to your websocket channel, you will use:
channel.sink.add("your data");
Finally, do not forget to close your websocket channel stream using:
channel.sink.close();
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.
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.
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. :)
Following is the code which listens on a port for HTTP requests and sends the request packet to the server running on port 80, gets the response and sends the data back to the client. Now, everything is executing fine but the following line of code :
data = req_soc.recv(1024)
is taking too much time to execute and I have observed that, it takes long time to execute when it is going to/has received the last packet. I have also tried the same code using select.select() but the results are the same. Since I want to handle the data (raw) that is coming from the client and the actual HTTP server, I have no other choice than using sockets.
import socket
import thread
def handle_client(client):
data = client.recv(512)
request = ''
request += data
print data
print '-'*20
spl = data.split("\r\n")
print spl[0]
print spl[1]
if len(request):
req_soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
req_soc.connect(('localhost', 80))
req_soc.send(request)
response = ''
data = req_soc.recv(1024)
while data:
response += data
print 1
data = req_soc.recv(1024)
req_soc.close()
print response
if len(response):
client.send(response)
client.close()
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 4422))
server.listen(5)
print("Server is running...\n")
MSGLEN = 1024
while 1:
client, address = server.accept()
thread.start_new_thread(handle_client, (client, ))
Clients can do multiple commands (eg: GET) within one connection. You cannot wait for the client to send all the commands because based on what you return it could request more (eg: images of a web page). You have to parse the parts (commands) of request, find the boundary, forward that request to the server and write back the answer to the client. All this in a way that doesn't block on reading the client.
I'm not sure what's the best way to do this in python, but if you spend 5 minutes of googling you'll find a perfect HTTP proxy library.