Closed kolinfluence closed 6 months ago
got it working this way, comments / feedback appreciated:
package main
import (
"bytes"
"flag"
"fmt"
"log"
"sync/atomic"
"time"
cxstrconv "github.com/cloudxaas/gostrconv"
"github.com/panjf2000/gnet/v2"
"github.com/valyala/bytebufferpool"
"github.com/leslie-fei/gnettls"
"github.com/leslie-fei/gnettls/tls"
)
type httpServer struct {
gnet.BuiltinEventEngine
addr string
multicore bool
eng gnet.Engine
}
type httpCodec struct {
buf *bytebufferpool.ByteBuffer // Main buffer reused for all I/O operations
headersBuffer []byte // Buffer containing all headers as raw bytes
method []byte // Method as a slice of headersBuffer
uri []byte // URI as a slice of headersBuffer
host []byte // Host as a slice of headersBuffer
}
var (
responseHeader = []byte("HTTP/1.1 200 OK\r\nServer: gnet\r\nContent-Type: text/plain\r\nDate: ")
now atomic.Value
bufferPool bytebufferpool.Pool
)
func updateCurrentTime() {
now.Store(time.Now().Format(time.RFC1123))
}
func (hc *httpCodec) appendResponse(body []byte) {
updateCurrentTime() // Update time only when responding
hc.buf.Reset()
hc.buf.Write(responseHeader)
hc.buf.WriteString(now.Load().(string))
hc.buf.WriteString("\r\nContent-Length: ")
hc.buf.WriteString(cxstrconv.Inttoa(len(body)))
hc.buf.WriteString("\r\n\r\n")
hc.buf.Write(body)
}
func (hc *httpCodec) parse(data []byte) error {
idx := bytes.Index(data, []byte("\r\n\r\n"))
if idx == -1 {
return fmt.Errorf("incomplete headers")
}
hc.headersBuffer = data[:idx] // Store only header part
lines := bytes.Split(hc.headersBuffer, []byte("\r\n"))
if len(lines) < 1 {
return fmt.Errorf("invalid request")
}
requestLine := bytes.SplitN(lines[0], []byte(" "), 3)
if len(requestLine) < 3 {
return fmt.Errorf("invalid request line")
}
hc.method, hc.uri = requestLine[0], requestLine[1]
for _, line := range lines[1:] {
if bytes.HasPrefix(line, []byte("Host: ")) {
hc.host = line[6:]
}
}
return nil
}
func route(hc *httpCodec) {
var response []byte
if bytes.Equal(hc.method, []byte("GET")) {
switch {
case bytes.Equal(hc.uri, []byte("/hello")):
response = []byte("Hello, World!")
case bytes.Equal(hc.uri, []byte("/time")):
response = []byte("Current Time: " + now.Load().(string))
default:
response = []byte("404 Not Found")
}
} else {
response = []byte("405 Method Not Allowed")
}
hc.appendResponse(response)
}
func (hs *httpServer) OnBoot(eng gnet.Engine) gnet.Action {
hs.eng = eng
log.Printf("HTTP server with multi-core=%t is listening on %s\n", hs.multicore, hs.addr)
return gnet.None
}
func (hs *httpServer) OnOpen(c gnet.Conn) ([]byte, gnet.Action) {
buf := bufferPool.Get()
c.SetContext(&httpCodec{buf: buf})
return nil, gnet.None
}
func (hs *httpServer) OnClose(c gnet.Conn, err error) gnet.Action {
if hc, ok := c.Context().(*httpCodec); ok {
bufferPool.Put(hc.buf)
} else {
// Adjusted to not log unexpected context type to handle mixed connection types gracefully
}
return gnet.None
}
func (hs *httpServer) OnTraffic(c gnet.Conn) gnet.Action {
hc, ok := c.Context().(*httpCodec)
if !ok {
log.Printf("DDSDASD")
return gnet.Close // Silently handle the mismatch, assuming context may be overridden by TLS
}
buf, _ := c.Next(-1)
if err := hc.parse(buf); err != nil {
log.Printf("Error parsing request from %s: %v", c.RemoteAddr().String(), err)
return gnet.Close
}
route(hc)
c.Write(hc.buf.B)
return gnet.None
}
func mustLoadCertificate() tls.Certificate {
cert, err := tls.LoadX509KeyPair("server.crt", "server.key")
if err != nil {
log.Fatalf("Failed to load server certificate: %v", err)
}
return cert
}
func main() {
var port int
var multicore bool
flag.IntVar(&port, "port", 8080, "server port")
flag.BoolVar(&multicore, "multicore", true, "use multicore")
flag.Parse()
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{mustLoadCertificate()},
}
addr := fmt.Sprintf("tcp://:%d", port)
hs := &httpServer{addr: addr, multicore: multicore}
options := []gnet.Option{
gnet.WithMulticore(multicore),
gnet.WithTCPKeepAlive(time.Minute * 5),
gnet.WithReusePort(true),
}
log.Fatal(gnettls.Run(hs, hs.addr, tlsConfig, options...))
}
Actions I've taken before I'm here
Questions with details
@leslie-fei
can u help run this code and provide the "debug" solution? i'm updating my repo to use tls. hope panjf can pull it soon.
i will help create examples for use with this tls
my original old code not sure how to port it anymore.
it runs but will crash when http request is suggested. possible to provide the solution fix to this?
Code snippets (optional)
No response