Skip to content

Commit 99eb09b

Browse files
committed
added docs for part 7 walkthrough
1 parent f936a1c commit 99eb09b

File tree

2 files changed

+211
-0
lines changed

2 files changed

+211
-0
lines changed
+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# Netrunner: Building HTTP from the Ground Up
2+
## Part 7: Implementing HTTPS
3+
4+
Welcome to Part 7 of our series on building HTTP from the ground up! In this installment, we'll focus on implementing HTTPS (HTTP Secure) to encrypt communications between clients and our server.
5+
6+
### Understanding HTTPS
7+
8+
HTTPS is an extension of HTTP that uses TLS (Transport Layer Security) for secure communication over a computer network. It provides:
9+
10+
1. Encryption: Protecting the exchanged data from eavesdropping and tampering
11+
2. Authentication: Ensuring that the server is who it claims to be
12+
3. Integrity: Verifying that the data hasn't been forged or tampered with
13+
14+
### Generating a Self-Signed Certificate
15+
16+
For development purposes, we'll create a self-signed certificate. In a production environment, you'd use a certificate signed by a trusted Certificate Authority.
17+
18+
Run the following command to generate a self-signed certificate and private key:
19+
20+
```bash
21+
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
22+
```
23+
24+
This will create two files: `key.pem` (private key) and `cert.pem` (certificate).
25+
26+
### Implementing HTTPS Server
27+
28+
Let's update our `main.go` to support both HTTP and HTTPS:
29+
30+
```go
31+
package main
32+
33+
import (
34+
"crypto/tls"
35+
"fmt"
36+
"net"
37+
"os"
38+
"os/signal"
39+
"syscall"
40+
41+
"github.com/yourusername/netrunner/pkg/http"
42+
)
43+
44+
var connPool *http.ConnPool
45+
46+
func main() {
47+
router := http.NewRouter()
48+
49+
// Add middleware
50+
router.Use(http.LoggingMiddleware)
51+
52+
// Add routes
53+
router.AddRoute("GET", "/", handleRoot)
54+
router.AddRoute("GET", "/hello", handleHello)
55+
router.AddRoute("POST", "/echo", handleEcho)
56+
57+
// Add static file handler
58+
execPath, _ := os.Executable()
59+
execDir := filepath.Dir(execPath)
60+
publicPath := filepath.Join(execDir, "public")
61+
staticHandler := http.StaticFileHandler(publicPath)
62+
router.AddRoute("GET", "/static/", staticHandler)
63+
64+
connPool = http.NewConnPool(100)
65+
66+
// Start HTTP server
67+
go startServer("http", ":8080", router)
68+
69+
// Start HTTPS server
70+
go startServer("https", ":8443", router)
71+
72+
// Wait for interrupt signal to gracefully shut down the servers
73+
quit := make(chan os.Signal, 1)
74+
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
75+
<-quit
76+
77+
fmt.Println("Server is shutting down...")
78+
connPool.CloseIdleConnections()
79+
fmt.Println("Server stopped")
80+
}
81+
82+
func startServer(protocol string, address string, router *http.Router) {
83+
var listener net.Listener
84+
var err error
85+
86+
if protocol == "https" {
87+
// Load TLS certificate and key
88+
cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
89+
if err != nil {
90+
fmt.Printf("Failed to load TLS certificate: %v\n", err)
91+
return
92+
}
93+
94+
tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}}
95+
listener, err = tls.Listen("tcp", address, tlsConfig)
96+
} else {
97+
listener, err = net.Listen("tcp", address)
98+
}
99+
100+
if err != nil {
101+
fmt.Printf("Failed to start %s server: %v\n", protocol, err)
102+
return
103+
}
104+
defer listener.Close()
105+
106+
fmt.Printf("%s server listening on %s\n", protocol, address)
107+
108+
for {
109+
conn, err := listener.Accept()
110+
if err != nil {
111+
fmt.Printf("Failed to accept connection: %v\n", err)
112+
continue
113+
}
114+
go handleConnection(conn, router)
115+
}
116+
}
117+
118+
func handleConnection(conn net.Conn, router *http.Router) {
119+
defer connPool.Put(conn)
120+
121+
var tlsConn *tls.ConnectionState
122+
if tlsConnection, ok := conn.(*tls.Conn); ok {
123+
state := tlsConnection.ConnectionState()
124+
tlsConn = &state
125+
}
126+
127+
buffer := make([]byte, 1024)
128+
n, err := conn.Read(buffer)
129+
if err != nil {
130+
handleConnectionError(conn, err)
131+
return
132+
}
133+
134+
request, err := http.ParseRequest(buffer[:n], tlsConn)
135+
if err != nil {
136+
handleHTTPError(conn, http.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid request: %v", err)))
137+
return
138+
}
139+
140+
response := router.HandleRequest(request)
141+
_, err = conn.Write(http.FormatResponse(response))
142+
if err != nil {
143+
fmt.Printf("Error writing response: %v\n", err)
144+
}
145+
}
146+
147+
// ... (other handler functions remain the same)
148+
```
149+
150+
### Updating the Request Structure
151+
152+
We need to update our `Request` structure to include TLS information. Update `pkg/http/request.go`:
153+
154+
```go
155+
package http
156+
157+
import "crypto/tls"
158+
159+
type Request struct {
160+
Method string
161+
Path string
162+
Version string
163+
Headers map[string]string
164+
Body []byte
165+
TLS *tls.ConnectionState
166+
}
167+
168+
// Update ParseRequest function to set TLS info
169+
func ParseRequest(data []byte, tlsConn *tls.ConnectionState) (*Request, error) {
170+
// ... (previous parsing logic)
171+
172+
request.TLS = tlsConn
173+
174+
return request, nil
175+
}
176+
```
177+
178+
### Testing HTTPS
179+
180+
To test HTTPS functionality:
181+
182+
1. Run your server:
183+
```bash
184+
go run cmd/server/main.go
185+
```
186+
187+
2. Open a web browser and navigate to `https://localhost:8443`
188+
(You'll see a security warning because we're using a self-signed certificate. In a real-world scenario, you'd use a certificate from a trusted CA.)
189+
190+
3. You can also use curl to test:
191+
```bash
192+
curl -k https://localhost:8443
193+
```
194+
The `-k` option tells curl to accept self-signed certificates.
195+
196+
### Conclusion
197+
198+
In this part, we've successfully implemented HTTPS support for our Netrunner server:
199+
200+
1. We generated a self-signed certificate for testing purposes.
201+
2. We updated our server to support both HTTP and HTTPS connections.
202+
3. We modified our `Request` structure to include TLS information.
203+
204+
These changes significantly improve the security of our server by encrypting all communications over HTTPS.
205+
206+
If you want to get new part pls follow me on twitter: [my twitter](https://x.com/minamisatokun) to stay tuned

pkg/http/router.go

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ type (
1212
MiddlewareFunc func(HandlerFunc) HandlerFunc
1313
)
1414

15+
type Route struct {
16+
Method string
17+
PathPattern string
18+
}
19+
1520
type Router struct {
1621
routes map[string]map[string]HandlerFunc
1722
middleware []MiddlewareFunc

0 commit comments

Comments
 (0)