receive HTTP request success; still working on response

This commit is contained in:
soypat
2025-05-31 14:08:32 -03:00
parent 0008791bd8
commit 1ae8fab210
4 changed files with 119 additions and 54 deletions
+26 -17
View File
@@ -61,6 +61,7 @@ func main() {
fmt.Println("hosting server at ", addrPort.String(), "over tap interface of mtu:", mtu, "prefix:", ippfx, "gateway:", net.HardwareAddr(gatewayMAC[:]).String()) fmt.Println("hosting server at ", addrPort.String(), "over tap interface of mtu:", mtu, "prefix:", ippfx, "gateway:", net.HardwareAddr(gatewayMAC[:]).String())
buf := make([]byte, mtu) buf := make([]byte, mtu)
var hdr httpraw.Header var hdr httpraw.Header
hdr.Reset(make([]byte, 0, 1024))
for { for {
nread, err := tap.Read(buf[:]) nread, err := tap.Read(buf[:])
if err != nil { if err != nil {
@@ -74,6 +75,7 @@ func main() {
slogger.error("recv", slog.String("err", err.Error()), slog.Int("plen", nread)) slogger.error("recv", slog.String("err", err.Error()), slog.Int("plen", nread))
} }
} }
doHTTP(handler, &hdr)
nw, err := lStack.HandleEth(buf[:]) nw, err := lStack.HandleEth(buf[:])
debugEthPacket(nil, "OUT", buf[:nw]) debugEthPacket(nil, "OUT", buf[:nw])
if err != nil { if err != nil {
@@ -87,29 +89,36 @@ func main() {
slogger.info("write", slog.Int("plen", nw)) slogger.info("write", slog.Int("plen", nw))
} }
} }
if handler.State() == tcp.StateEstablished {
data := handler.BufferedInput()
if data > 0 {
n, err := handler.Read(buf[:])
if err != nil {
slogger.error("tcp-read", slog.String("err", err.Error()))
} else {
hdr.Reset(buf[:n])
err = hdr.Parse(false)
if err != nil {
slogger.error("http-parse", slog.String("err", err.Error()))
} else {
fmt.Println(hdr.String())
}
}
}
}
if nread == 0 && nw == 0 { if nread == 0 && nw == 0 {
time.Sleep(5 * time.Millisecond) time.Sleep(5 * time.Millisecond)
} }
} }
} }
func doHTTP(conn *internet.TCPConn, hdr *httpraw.Header) error {
const asRequest = false
if conn.State() != tcp.StateEstablished || conn.BufferedInput() == 0 {
return nil // No data yet.
}
fmt.Println("state is established; check request and send response")
_, err := hdr.ReadFromLimited(conn, hdr.Free())
if err != nil {
return err
}
needMore, err := hdr.TryParse(asRequest)
if err != nil {
if !needMore {
fmt.Println("IT's SO GOVER")
conn.Close()
}
return err
}
// HTTP parsed succesfully!
fmt.Println("GOT HTTP:\n", hdr.String())
return nil
}
func NewEthernetTCPStack(ourMAC, gwMAC [6]byte, ip netip.AddrPort, mtu uint16, slogger logger) (*LinkStack, *internet.TCPConn, error) { func NewEthernetTCPStack(ourMAC, gwMAC [6]byte, ip netip.AddrPort, mtu uint16, slogger logger) (*LinkStack, *internet.TCPConn, error) {
var err error var err error
lStack := LinkStack{ lStack := LinkStack{
+34 -8
View File
@@ -4,6 +4,8 @@ import (
"fmt" "fmt"
"net" "net"
"os" "os"
"os/signal"
"syscall"
"github.com/soypat/lneto/http/httpraw" "github.com/soypat/lneto/http/httpraw"
) )
@@ -17,27 +19,51 @@ func main() {
} }
func run() error { func run() error {
// Prepare GET request.
var hdr httpraw.Header
hdr.SetMethod("GET")
hdr.SetRequestURI("/")
hdr.SetProtocol("HTTP/1.1")
req, err := hdr.AppendRequest(nil)
if err != nil {
return err
}
fmt.Println("dialing...") fmt.Println("dialing...")
conn, err := net.DialTCP("tcp4", &net.TCPAddr{IP: []byte{192, 168, 10, 1}, Port: 1337}, &net.TCPAddr{IP: []byte{192, 168, 10, 2}, Port: 80}) conn, err := net.DialTCP("tcp4", &net.TCPAddr{IP: []byte{192, 168, 10, 1}, Port: 1337}, &net.TCPAddr{IP: []byte{192, 168, 10, 2}, Port: 80})
if err != nil { if err != nil {
return err return err
} }
defer conn.Close()
go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
s := <-c
fmt.Println("terminating connection on signal", s.String())
conn.Close()
os.Exit(0)
}()
fmt.Println("reading...") fmt.Println("reading...")
var hdr httpraw.Header conn.Write(req)
for {
hdr.Reset(nil)
var needMore bool = true
for needMore {
_, err = hdr.ReadFromLimited(conn, 1024) _, err = hdr.ReadFromLimited(conn, 1024)
if err != nil { if err != nil {
return err break
} }
const asRequest = false const asResponse = true
var ok bool needMore, err = hdr.TryParse(asResponse)
ok, err = hdr.TryParse(asRequest) if needMore {
if ok {
break break
} else if err != nil { } else if err != nil {
return err break
} }
} }
if err != nil {
return err
}
fmt.Println("got HTTP:\n", hdr.String()) fmt.Println("got HTTP:\n", hdr.String())
return nil return nil
} }
+23 -9
View File
@@ -24,6 +24,7 @@ const (
flagConnClose flagConnClose
flagNoHTTP11 flagNoHTTP11
flagMangledBuffer // set when header fields appended to buffer via Add,Set calls flagMangledBuffer // set when header fields appended to buffer via Add,Set calls
flagReaderEOF
) )
func (f flags) hasAny(checkThese flags) bool { func (f flags) hasAny(checkThese flags) bool {
@@ -77,20 +78,21 @@ func (h *Header) Parse(asResponse bool) error {
} }
// TryParse begins parsing or resumes parsing from a failed previous attempt from any of the Parse* methods. // TryParse begins parsing or resumes parsing from a failed previous attempt from any of the Parse* methods.
// It fails if HTTP data is incomplete. It panics if called after header parsing completed succesfully. // As long as needMoreData returns true future calls to TryParse may succeed and the header is not done parsing.
// As long as ok returns true future calls to TryParse may succeed.
// //
// ok, err := h.TryParse() // needMoreData := true
// for ; ok; ok, err = h.TryParse() { // var err error
// _, err = h.ReadFrom(r, 256) // for needMoreData {
// if err != nil && err != io.EOF { // _, err = h.ReadFrom(r, 1024)
// return err // if err != nil {
// break
// } // }
// needMoreData, err = h.TryParse()
// } // }
// if err != nil { // if err != nil {
// return err // return err
// } // }
func (h *Header) TryParse(asResponse bool) (ok bool, err error) { func (h *Header) TryParse(asResponse bool) (needMoreData bool, err error) {
if h.flags.hasAny(flagDoneParsingHeader) { if h.flags.hasAny(flagDoneParsingHeader) {
return false, errors.New("TryParse called after header parsed") return false, errors.New("TryParse called after header parsed")
} else if h.flags.hasAny(flagMangledBuffer) { } else if h.flags.hasAny(flagMangledBuffer) {
@@ -103,11 +105,12 @@ func (h *Header) TryParse(asResponse bool) (ok bool, err error) {
} }
} }
err = h.parseNextHeaders() err = h.parseNextHeaders()
return err == nil || err == errNeedMore, err return err == errNeedMore, err
} }
// ReadFromLimited reads at most maxBytesToRead from reader and appends them to underlying buffer. // ReadFromLimited reads at most maxBytesToRead from reader and appends them to underlying buffer.
// Used to accumulate HTTP header for later parsing with [Header.TryParse]. // Used to accumulate HTTP header for later parsing with [Header.TryParse].
// If read is successful (read length>0) and reader returns [io.EOF] then ReadFromLimited will return a nil error.
func (h *Header) ReadFromLimited(r io.Reader, maxBytesToRead int) (int, error) { func (h *Header) ReadFromLimited(r io.Reader, maxBytesToRead int) (int, error) {
if maxBytesToRead <= 0 { if maxBytesToRead <= 0 {
return 0, errSmallBuffer return 0, errSmallBuffer
@@ -124,6 +127,12 @@ func (h *Header) ReadFromLimited(r io.Reader, maxBytesToRead int) (int, error) {
blen := len(h.hbuf.buf) blen := len(h.hbuf.buf)
b := h.hbuf.buf[blen:min(blen+maxBytesToRead, cap(h.hbuf.buf))] b := h.hbuf.buf[blen:min(blen+maxBytesToRead, cap(h.hbuf.buf))]
n, err := r.Read(b) n, err := r.Read(b)
if err != nil && err == io.EOF {
h.flags |= flagReaderEOF
if n > 0 {
err = nil // Nil-out error if read was succesful so as to not spook readers.
}
}
h.hbuf.buf = h.hbuf.buf[:blen+n] h.hbuf.buf = h.hbuf.buf[:blen+n]
return n, err return n, err
} }
@@ -150,6 +159,11 @@ func (h *Header) Free() int {
return h.hbuf.free() return h.hbuf.free()
} }
// Capacity returns the total capacity of the underlying buffer.
func (h *Header) Capacity() int {
return cap(h.hbuf.buf)
}
// ForEach iterates over header key-value field tuples. // ForEach iterates over header key-value field tuples.
func (h *Header) ForEach(cb func(key, value []byte) error) error { func (h *Header) ForEach(cb func(key, value []byte) error) error {
return h.hbuf.forEach(cb) return h.hbuf.forEach(cb)
+36 -20
View File
@@ -56,7 +56,7 @@ func (h *HTTPTapClient) ensureMTU() (err error) {
if err != nil { if err != nil {
return err return err
} }
var info TapInfo var info tapInfo
err = json.NewDecoder(resp.Body).Decode(&info) err = json.NewDecoder(resp.Body).Decode(&info)
if err != nil { if err != nil {
return err return err
@@ -85,40 +85,56 @@ type HTTPTapClient struct {
buf []byte buf []byte
} }
func (h *HTTPTapClient) ReadDiscard() { func (h *HTTPTapClient) ReadDiscard() error {
var data [2048]byte for {
var n int = -1 d, _ := h.ReadBytes() // Empty remote data.
for n != 0 { if len(d) == 0 {
n, _ = h.Read(data[:]) // Empty remote data. break
}
} }
return nil
}
func (h *HTTPTapClient) ReadBytes() (data []byte, err error) {
err = h.ensureMTU()
if err != nil {
return nil, err
}
resp, err := h.c.Get(h.recvurl)
if err != nil {
return nil, err
} else if resp.StatusCode != 200 {
return nil, errors.New(resp.Status + " for " + h.recvurl)
}
buf := h.buf
err = json.NewDecoder(resp.Body).Decode(&buf)
if err != nil {
return nil, err
}
return buf, nil
} }
func (h *HTTPTapClient) Read(b []byte) (int, error) { func (h *HTTPTapClient) Read(b []byte) (int, error) {
err := h.ensureMTU() err := h.ensureMTU()
if err != nil { if err != nil {
return 0, err return 0, err
} else if len(b) < h.MTU() {
return 0, errors.New("buffer must have at least MTU size")
} }
resp, err := h.c.Get(h.recvurl) data, err := h.ReadBytes()
if err != nil { if err != nil {
return 0, err return 0, err
} else if resp.StatusCode != 200 {
return 0, errors.New(resp.Status + " for " + h.recvurl)
} }
var data []byte n := copy(b, data)
err = json.NewDecoder(resp.Body).Decode(&data) return n, nil
if err != nil {
return 0, err
} else if len(b) < len(data) {
return 0, fmt.Errorf("got too large packet %d for buffer %d", len(data), len(b))
}
copy(b, data)
return len(data), nil
} }
func (h *HTTPTapClient) Write(b []byte) (int, error) { func (h *HTTPTapClient) Write(b []byte) (int, error) {
err := h.ensureMTU() err := h.ensureMTU()
if err != nil { if err != nil {
return 0, err return 0, err
} else if len(b) > h.MTU() {
return 0, errors.New("buffer larger than MTU")
} }
data, _ := json.Marshal(b) data, _ := json.Marshal(b)
resp, err := h.c.Post(h.sendurl, "application/json", bytes.NewReader(data)) resp, err := h.c.Post(h.sendurl, "application/json", bytes.NewReader(data))
@@ -140,7 +156,7 @@ type HTTPTapServer struct {
tapfailed bool tapfailed bool
} }
type TapInfo struct { type tapInfo struct {
MTU int MTU int
IPPrefix string IPPrefix string
HardwareAddr string HardwareAddr string
@@ -185,7 +201,7 @@ func NewHTTPTapServer(iface string, ip netip.Prefix, mtu, queueOut, queueIn int)
}) })
ipstr := ip.String() ipstr := ip.String()
sv.HandleFunc("/info", func(w http.ResponseWriter, r *http.Request) { sv.HandleFunc("/info", func(w http.ResponseWriter, r *http.Request) {
info := TapInfo{ info := tapInfo{
MTU: mtu, MTU: mtu,
IPPrefix: ipstr, IPPrefix: ipstr,
} }