I am trying to implement a server in Python. When the browser connects to localhost with port number 9999, it will open the file index.html with the images.jpg in that page, but the image can not be shown. How can I make the web server handle the image as well?
Here is my code so far:
from socket import *
import os
serversocket = socket(AF_INET, SOCK_STREAM)
port = 5000
host = '127.0.0.1'
size = os.path.getsize("index.html")
myfile = open('index.html', 'rb')
mycontent = "Welcome to Very Simple Web Server"
size = len(mycontent)
header = "HTTP/1.0 200 OK \r\n Content_Length:" + str(size) + "\r\n\r\n"
mycontent = myfile.read()
serversocket.bind((host, port))
serversocket.listen(5)
print('Server is listening on port 9999')
while (1):
conn, addr = serversocket.accept()
print('Connected by', addr)
conn.send(bytes(header))
conn.send(mycontent)
conn.close()
Your code creates an infinite loop that will just only send one file, and never accepts other connections.
In order for the image to show, the browser has to send another request to the URL of the image, and this request is not being serviced by your code.
In order for your server to work, you need to:
Start a loop
Listen for connections
Interpret the headers of the incoming request, and then act appropriately. Lets assume that you only deal with GET requests and not other things like POST, HEAD, PUT, etc.
Look at the requested resource (the URL)
Find the resource on the file system (so now, you have to parse the URL)
Package the resource into a HTTP response (read the file set the appropriate mime type)
Send the response back to the client with the appropriate headers (the server response headers)
Repeat
To display a HTML page with one image, it takes two requests, one for the HTML page, and another for the image. If the HTML code has a link to a CSS file, now you need three requests - one for the HTML page, one for the CSS file and a final one for the image. All these requests need to be completed successfully in order for the browser to render the page.
You never need to do this by hand, use a web development framework which will take care of all this "boring" stuff so you can then deal with solving the actual problem.
Related
I have the following code for a simple Server that handles GET requests from the browser over TCP.
while True:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('127.0.0.1', int(args.port)))
print(f'TCP Server listening on port {args.port}...')
s.listen()
connection, addr = s.accept()
print(f'Connected by {addr}')
while True:
data = connection.recv(args.buf)
if not data:
print('Connection closed')
break
message = data.decode()
response = handle_request(message)
connection.sendall(response)
connection.close()
This works somewhat, but not really. When the browser GETs a PNG or html file, that it has cached (if-modified-since), it works seamlessly. However, when it has to serve a new file, the browser (Safari) stalls until I shut down the server but then mysteriously shows the actual file the browser was trying to GET.
I wonder if this has something to do with my implementation of the connection, but I assume that it more likely has to do with my http headers.
This is what my simple headers and response to the browser look like:
header = f"HTTP/1.1 {status}\r\n" \
f"Host: {header_dict['host']}\r\n" \
f"Date: {datetime.today().strftime(time_format)}\r\n" \
f"Last-Modified: {mod_time}\r\n" \
f"Connection: Keep-Alive\r\n" \
f"\r\n".encode()
with open(filename, "rb") as f:
payload = f.read()
response = header + payload
Is there anything important missing from the header for Safari (or any other browser) to work with it? Thanks!
As KompjoeFriek commented, the browser needs to know how much data it is getting from the server. So the content-length header is necessary when handling a get request to serve some data. Without it, it waits until the connection is closed to show the data it has received. Adding a content-length header solved the problem.
So, i am trying to create a simple server on python and trying to access a html file in the same directory through it, but as the output i keep on getting ready to serve...
output
EDIT:
Put an HTML file (e.g., HelloWorld.html) in the same directory that the server is in. Run the server program. Determine the IP address of the host that is running the server (e.g., 128.238.251.26). From another host, open a browser and provide the corresponding URL. For example:
http://128.238.251.26:6789/HelloWorld.html
‘HelloWorld.html’ is the name of the file you placed in the server directory. Note also the use of the port number after the colon. You need to replace this port number with whatever port you have used in the server code. In the above example, we have used the port number 6789. The browser should then display the contents of HelloWorld.html. If you omit ":6789", the browser will assume port 80 and you will get the web page from the server only if your server is listening at port 80.
Then try to get a file that is not present at the server. You should get a “404 Not Found” message.
#import socket module
from socket import *
serverSocket = socket(AF_INET, SOCK_STREAM)
#Prepare a sever socket
serverSocket.bind(('', 12006))
serverSocket.listen(1)
while True:
print 'Ready to serve...'
#Establish the connection
connectionSocket, addr = serverSocket.accept()
try:
message = connectionSocket.recv(1024)
filename = message.split()[1]
f = open(filename[1:])
outputdata = f.read()
f.close()
#Send one HTTP header line into socket
connectionSocket.send('HTTP/1.0 200 OK\r\n\r\n')
#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:
#Send response message for file not found
connectionSocket.send('404 Not Found')
#Close client socket
connectionSocket.close()
serverSocket.close()
Your output is a standart output, that used through print function. you should to make a request to your server and you'll get the correct output
If your server on your local machine, you should use localhost address; if not, you should use your server ip. Also you should to specify a port. 12006 in your case. localhost:12006 as an example
Also socket.send method requires a byte-like object. not string
If it's only a string literal, you should to add a b character before the first quotation mark
Example:
connectionSocket.send(b'HTTP/1.0 200 OK\r\n\r\n')
If it is a string object, you should to encode it:
connectionSocket.send(outputdata[i].encode())
Check out the documentation
I have been working on this program which basically sends an HTML request to the specified server, but each time I run it to send a GET request it responds with a 404 not found page of that site. Can anybody please guide what am I doing wrong out here? I tried copying the Firefox HTML request file and sending that still no use.
import socket
server,port = 'google.com',80
ip = socket.gethostbyname(server)
print (ip)
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((server,port))
request = 'GET /HTTP/1.1\nHost: '+str(ip)+'\n\n'
print(request)
sock.sendall(request.encode())
while True:
data = ' '
data = sock.recv(4096)
if data == ' ':
break
print(data.decode())
And also what are the applications of socket module apart from creating remote servers?
I think your problem is your request. First, you need a space after that first /. Second, for the host, it should be www.google.com, not an IP address.
request = 'GET / HTTP/1.1 \nHost: www.google.com\n\n'
Also, you should change that first line to www.google.com, since it will redirect you there anyway:
server,port = 'www.google.com',80
I am sending some data after html content (it has a little delay) in the same response during keep-alive session and want browser to show html before the whole response is downloaded.
For example, I have text 'hello, ' and a function that computes 'world' with delay (let it be 1 sec). So I want browser to show 'hello, ' immediately and 'world' with its delay. Is it possible within one request (so, without ajax)
Here is example python code of what I do (highlighted: https://pastebin.com/muUJyR36):
import socket
from time import sleep
sock = socket.socket()
sock.bind(('', 9090))
sock.listen(1)
conn, addr = sock.accept()
def give_me_a_world():
sleep(1)
return b'world'
while True:
data = conn.recv(1024)
response = b'HTTP/1.1 200 OK\r\n'\
b'Content-Length: 12\r\n'\
b'Connection: keep-alive\r\n'\
b'\r\n'\
b'hello, '
conn.send(response) # send first part
conn.send(give_me_a_world()) # make a delay and send other part
conn.close()
First and foremost, read How the web works: HTTP and CGI explained to understand why and where your current code violates HTTP and thus doesn't and shouldn't work.
Now, as per Is Content-Length or Transfer-Encoding is mandatory in a response when it has body , after fixing the violation, you should
omit the Content-Length header and close the socket after sending all the data, OR
calculate the length of the entire data to send beforehand and specify it in the Content-Length header
You could use Transfer-Encoding: chunked and omit Content-Length.
It works fine on text browsers like curl and Links WWW Browser. But, modern graphical browsers don't really start rendering until it reaches some sort of buffer boundaries.
import socket
from time import sleep
sock = socket.socket()
sock.bind(('', 9090))
sock.listen(1)
conn, addr = sock.accept()
def give_me_a_world():
sleep(1)
return b'5\r\n'\
b'world\r\n'\
b'0\r\n'\
b'\r\n'
while True:
data = conn.recv(1024)
response = b'HTTP/1.1 200 OK\r\n'\
b'Transfer-Encoding: chunked\r\n'\
b'Connection: keep-alive\r\n'\
b'\r\n'\
b'7\r\n'\
b'hello, \r\n'
conn.send(response) # send first part
conn.send(give_me_a_world()) # make a delay and send other part
conn.close()
I'm trying to create a simple web browser.
I have an index.html file placed in my local. I'm trying to start a client server connection and then display the html file in the browser.
I'm able to open the index.html file and read it's contents except some of it's contents. There are links which point to the images in the local directory, but when clicked on it in browser, it's not opening.
Here is the sample code.
HOST, PORT = '', 8888
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)
listen_socket.listen(1)
print('Serving HTTP on port %s ...' % PORT)
os.chdir("some directory where index.html is present")
open_file=open('index.html','r')
print(os.getcwd())
#http_response=open_file.read()
""" sample html code where image exists
<image src="./images/welcome.png" height=180px />
The index.html is perfectly fine, but i'm not able to display the images
in browser"""
while True:
client_connection, client_address = listen_socket.accept()
request = client_connection.recv(1024)
print(request.decode('utf-8'))
http_response = open_file.read()
client_connection.sendall((str.encode(http_response)))
client_connection.close()
Is there some kind of special encoding that needs to be done for displaying images?
Please note that I can't use any external modules.
For the content to be treated as a valid html file, one needs to send the required content's which are treated as some kind of rule set to the decoder like browser to realize that it should treat it has a protocol of HTTP/1.1 and also the Content Type is of type html and so add:
client_connection.send('HTTP/1.1 200 OK\nContent-Type: text/html\n\n')
before
client_connection.sendall(http_response.encode('UTF-8'))