Last Updated
Viewed 3,766 Times
              

I need to build a http server without using an HTTP library.

I have the server running and an html page beeing loaded but my <img src="..."/> tags are not beeing loaded, I recive the call but cannot preset the png/JPEG in the page.

httpServer.py

# Define socket host and port
SERVER_HOST = '0.0.0.0'
SERVER_PORT = 8000

# Create socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((SERVER_HOST, SERVER_PORT))
server_socket.listen(1)
print('Listening on port %s ...' % SERVER_PORT)

while True:
    # Wait for client connections
    client_connection, client_address = server_socket.accept()

    # Handle client request
    request = client_connection.recv(1024).decode()
    content = handle_request(request)

    # Send HTTP response
    if content:
        response = 'HTTP/1.1 200 OK\n\n'
        response += content
    else:
        response = 'HTTP/1.1 404 NOT FOUND\n\nFile Not Found'

    client_connection.sendall(response.encode())
    client_connection.close()

# Close socket
server_socket.close()

Function where handles the call

 def handle_request(request):
    http = HttpHandler.HTTPHandler

    # Parse headers
    print(request)
    headers = request.split('\n')
    get_content = headers[0].split()

    accept = headers[6].split()
    type_content = accept[1].split('/')

    try:
        # Filename
        filename = get_content[1]

        if get_content[0] == "GET":
            content = http.get(None, get_content[1], type_content[0])


        return content
    except FileNotFoundError:
        return None

class to handle the http verbs

class HTTPHandler:

    def get(self, args, type):
        if args == '/':
            args = '/index.html'
            fin = open('htdocs' + args)
        if type != "image":
            fin = open('htdocs/' + args)

        if type == "image":
            fin = open('htdocs/' + args, 'rb')

        # Read file contents
        content = fin.read()
        fin.close()
        return content

Realize that I´m trying to make an HTTP 1.1, if you see anything out of pattern fell free to say thanks in advance.

So as my title said, Im making a small http library with basic get and post requests. I have the get request done, but my post request is acting weird. Anytime I pass data to the post, it doesn't get a response. It seems to work just fine when I don't pass the body attribute (last one). Im not trying to use the requests library, i'm trying to make one myself.

Can anyone see what I'm doing wrong? I feel like I am missing a header but I don't know which.

import socket
from urllib.parse import urlparse
import json

TCRLF = "\r\n\r\n"
CRLF = "\r\n"



def post(url, headers=None, data=""):

    connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    request = build_request("POST", url, headers, data)
    print("request: " + request)
    print("url:" + url)
    print("headers :" + str(headers))

    url = urlparse(url)

    connection.connect((url.hostname, url.port or 80))
    connection.sendall(request.encode("UTF-8"))
    response = connection.recv(4096).decode("UTF-8")
    print("response: " +  response)
    #
    # (response_header, response_body) = response.split(TCRLF)
    # response_body = json.loads(response_body)
    #
    # print(response_header)
    # print(response_body)

    return None

def build_request(req_type, url, headers=None, body=""):

    url = urlparse(url)

    hostname = url.hostname
    path = url.path or "/"
    query = url.query
    port = url.port or 80

    print("hostname" + hostname)
    print("path : " + path)
    print("query :" + query)
    print("port :" + str(port))
    print("body:" + str(body))

    uri = "{}?{}".format(path, query) if query else path

    formatted_headers = "".join(
        "{}:{}\r\n".format(k, v) for k, v in headers.items())


    print("formatted: "+ formatted_headers)

    requestGet = "GET " + uri + " HTTP/1.0" + CRLF + "Host:" + hostname + CRLF + formatted_headers + TCRLF

    ##TODO body failing when passing object
    requestPost = "POST " + uri + " HTTP/1.0" + CRLF + "Host: " + hostname + CRLF + "Content-Length: " + str(
        len(body)) + CRLF + formatted_headers + TCRLF + body + TCRLF

    print("Request" + requestPost)

    if req_type=="POST":
        return requestPost
    else:
        return requestGet


def main():
    post("http://httpbin.org/post", {"Content-Type": "application/json" }, "{'Assignment': 1}")

if __name__ == '__main__':
    main()

I'm creating an HTTP server in Python without any of the HTTP libraries for learning purposes. Right now it can serve static files fine.

The way I serve the file is through this piece of code:

with open(self.filename, 'rb') as f:
    src = f.read()
socket.sendall(src)

However, I want to optimize its performance a bit by sending compressed data instead of uncompressed. I know that my browser (Chrome) accepts compressed data because it tells me in the header

Accept-Encoding: gzip, deflate, sdch

So, I changed my code to this

with open(self.filename, 'rb') as f:
    src = zlib.compress(f.read())
socket.sendall(src)

But this just outputs garbage. What am I doing wrong?

First off thanks for reading!

Second off YES I have tried to find the answer! :) Perhaps I haven't found it because I'm not using the right words to describe my problem, but it's been about 4 hours that I've been trying to figure it out now and I'm getting a little loopy trying to piece it together on my own.

I am very new to programming. Python is my first language. I am on my third Python course. I have an assignment to use the socket library (not urllib library - I know how to do that) to make a socket and use GET to receive information. The problem is that the program needs to take raw input for the URL in question.

I have everything else the way I want it, but I need to know the syntax that I'm supposed to be using INSIDE my "GET" request in order for the HTTP message to include the requested document path.

I have tried (obviously not all together lol):

mysock.send('GET (url) HTTP/1.0\n\n')
mysock.send( ('GET (url) HTTP:/1.0\n\n'))
mysock.send(('GET (url) HTTP:/1.0\n\n'))
mysock.send("GET (url) HTTP/1.0\n\n")
mysock.send( ("'GET' (url) HTTP:/1.0\n\n"))
mysock.send(("'GET' (url) 'HTTP:/1.0\n\n'"))

and:

basically every other configuration of the above (, ((, ( (, ', '' combinations listed above.

I have also tried:

-Creating a string using the 'url' variable first, and then including it inside mysock.send(string) -Again with the "string-first" theory, but this time I used %r to refer to my user input (so 'GET %r HTTP/1.0\n\n' % url basically)

I've read questions here, other programming websites, the whole chapter in the book and the whole lectures/notes online, I've read articles on the socket library and the .send(), and of course articles on GET requests... but I'm clearly missing something. It seems most don't use socket library when they can use urllib and I don't blame them!!

Thank you again...

Similar Question 4 (2 solutions) : Send text “http” over python socket

Similar Question 5 (1 solutions) : Can't get image data through socket HTTP request

Similar Question 7 (1 solutions) : http get request timeout

Similar Question 8 (1 solutions) : HTTP GET file extension support

Similar Question 9 (1 solutions) : What is the format of a HTTP PUT request?

cc