Motivation
I was curious how a http request was working. Yeah, I too had networking in my college, but wasn’t that curious back then. Now for living I do web development for past two years. I took a pause and wanted to know how things were working under the hood.
What are we builting
A http server in go, without a http package.
But why? There is a lot of framework that let you build stuff without much effort. We are explorers right? we want to know how things work.
The plan
“If you wish to make an apple pie from scratch, you must first invent the universe" ~ Carl Sagan
HTTP is built on top of TCP, which is responsible for sending the bytes from one machine to another. So our basic building block is TCP.
This is how our server works.
- listen to tcp connection on port
- run infinite loop to accept any request
- concurrently accept any request using thread
- send back a response
What happens when we make a request in browser
When we are looking for “http://localhost:3000” on a browser
- Browser will be sending a
http
get request to server. - Server listen to the request
- understands browser is requesting for index.html (whatever)
- send back the data to browser
- close the connection
Coding time
gist for the entire code
we will be exploring the important parts of the server.
- Listening to requests
func main() {
listener, err := net.Listen("tcp", ":8080")
if err != nil {
fmt.Println("Error starting server", err)
return
}
// free resourse when function returns
defer listener.Close()
// server is ok to start
fmt.Println("server is listening on port 8080")
// we need a infinite loop, which will serve the request
for {
// blocks the loop untill a request is made
conn, err := listener.Accept();
fmt.Println("conn is accepted")
if err != nil {
fmt.Println("Error accepting connection:", err)
continue
}
// handle the request
// it shouldn't block the next request
// so running in seperate thread
// this is go routine
go handleRequest(conn)
}
}
- Process the request and send back response
func handleRequest(conn net.Conn) {
defer conn.Close()
// send a response
response := "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello, world!"
conn.Write([]byte(response))
}
‘Hello, world!’ will be visible on the browser 😁.