mirror of
https://github.com/soypat/lneto.git
synced 2026-08-10 09:53:44 +00:00
receive HTTP request success; still working on response
This commit is contained in:
+26
-17
@@ -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{
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user