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())
buf := make([]byte, mtu)
var hdr httpraw.Header
hdr.Reset(make([]byte, 0, 1024))
for {
nread, err := tap.Read(buf[:])
if err != nil {
@@ -74,6 +75,7 @@ func main() {
slogger.error("recv", slog.String("err", err.Error()), slog.Int("plen", nread))
}
}
doHTTP(handler, &hdr)
nw, err := lStack.HandleEth(buf[:])
debugEthPacket(nil, "OUT", buf[:nw])
if err != nil {
@@ -87,29 +89,36 @@ func main() {
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 {
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) {
var err error
lStack := LinkStack{
+34 -8
View File
@@ -4,6 +4,8 @@ import (
"fmt"
"net"
"os"
"os/signal"
"syscall"
"github.com/soypat/lneto/http/httpraw"
)
@@ -17,27 +19,51 @@ func main() {
}
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...")
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 {
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...")
var hdr httpraw.Header
for {
conn.Write(req)
hdr.Reset(nil)
var needMore bool = true
for needMore {
_, err = hdr.ReadFromLimited(conn, 1024)
if err != nil {
return err
break
}
const asRequest = false
var ok bool
ok, err = hdr.TryParse(asRequest)
if ok {
const asResponse = true
needMore, err = hdr.TryParse(asResponse)
if needMore {
break
} else if err != nil {
return err
break
}
}
if err != nil {
return err
}
fmt.Println("got HTTP:\n", hdr.String())
return nil
}
+23 -9
View File
@@ -24,6 +24,7 @@ const (
flagConnClose
flagNoHTTP11
flagMangledBuffer // set when header fields appended to buffer via Add,Set calls
flagReaderEOF
)
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.
// It fails if HTTP data is incomplete. It panics if called after header parsing completed succesfully.
// As long as ok returns true future calls to TryParse may succeed.
// As long as needMoreData returns true future calls to TryParse may succeed and the header is not done parsing.
//
// ok, err := h.TryParse()
// for ; ok; ok, err = h.TryParse() {
// _, err = h.ReadFrom(r, 256)
// if err != nil && err != io.EOF {
// return err
// needMoreData := true
// var err error
// for needMoreData {
// _, err = h.ReadFrom(r, 1024)
// if err != nil {
// break
// }
// needMoreData, err = h.TryParse()
// }
// if err != nil {
// 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) {
return false, errors.New("TryParse called after header parsed")
} else if h.flags.hasAny(flagMangledBuffer) {
@@ -103,11 +105,12 @@ func (h *Header) TryParse(asResponse bool) (ok bool, err error) {
}
}
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.
// 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) {
if maxBytesToRead <= 0 {
return 0, errSmallBuffer
@@ -124,6 +127,12 @@ func (h *Header) ReadFromLimited(r io.Reader, maxBytesToRead int) (int, error) {
blen := len(h.hbuf.buf)
b := h.hbuf.buf[blen:min(blen+maxBytesToRead, cap(h.hbuf.buf))]
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]
return n, err
}
@@ -150,6 +159,11 @@ func (h *Header) Free() int {
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.
func (h *Header) ForEach(cb func(key, value []byte) error) error {
return h.hbuf.forEach(cb)
+36 -20
View File
@@ -56,7 +56,7 @@ func (h *HTTPTapClient) ensureMTU() (err error) {
if err != nil {
return err
}
var info TapInfo
var info tapInfo
err = json.NewDecoder(resp.Body).Decode(&info)
if err != nil {
return err
@@ -85,40 +85,56 @@ type HTTPTapClient struct {
buf []byte
}
func (h *HTTPTapClient) ReadDiscard() {
var data [2048]byte
var n int = -1
for n != 0 {
n, _ = h.Read(data[:]) // Empty remote data.
func (h *HTTPTapClient) ReadDiscard() error {
for {
d, _ := h.ReadBytes() // Empty remote data.
if len(d) == 0 {
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) {
err := h.ensureMTU()
if err != nil {
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 {
return 0, err
} else if resp.StatusCode != 200 {
return 0, errors.New(resp.Status + " for " + h.recvurl)
}
var data []byte
err = json.NewDecoder(resp.Body).Decode(&data)
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
n := copy(b, data)
return n, nil
}
func (h *HTTPTapClient) Write(b []byte) (int, error) {
err := h.ensureMTU()
if err != nil {
return 0, err
} else if len(b) > h.MTU() {
return 0, errors.New("buffer larger than MTU")
}
data, _ := json.Marshal(b)
resp, err := h.c.Post(h.sendurl, "application/json", bytes.NewReader(data))
@@ -140,7 +156,7 @@ type HTTPTapServer struct {
tapfailed bool
}
type TapInfo struct {
type tapInfo struct {
MTU int
IPPrefix string
HardwareAddr string
@@ -185,7 +201,7 @@ func NewHTTPTapServer(iface string, ip netip.Prefix, mtu, queueOut, queueIn int)
})
ipstr := ip.String()
sv.HandleFunc("/info", func(w http.ResponseWriter, r *http.Request) {
info := TapInfo{
info := tapInfo{
MTU: mtu,
IPPrefix: ipstr,
}