This repository has been archived by the owner on Dec 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
httpserver.go
159 lines (142 loc) · 4.49 KB
/
httpserver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package swtch
import (
"bytes"
"time"
"net"
"github.com/soypat/ether-swtch/grams"
"github.com/soypat/ether-swtch/lax"
"tinygo.org/x/drivers"
)
// HTTPListenAndServe spins up a blocking HTTP server on port 80.
//
// Not safe for multiple instantiations on same device. Concurrent use not tested.
func HTTPListenAndServe(dg drivers.Datagrammer, mac net.HardwareAddr, IPAddr net.IP, timeout time.Duration, handler func(URL []byte) (response []byte), errhandler func(error)) {
var count uint
var err error
var _http = HTTP{}
var httpf = &_http
// HTTP/TCP variables
var (
// HTTPLen variables accumulate total data sent by the client and server
clientHTTPLen, serverHTTPLen, ACK, SEQ uint32
response []byte
)
var conn TCPConn
err = conn.Init(dg, httpf, timeout, mac, IPAddr, 80)
if err != nil {
panic(err.Error())
}
// conn := newTCPconn(dg, httpf, timeout, mac, IPAddr, 80)
// declare shorthand frames
eth := &conn.Ethernet
ipf := &conn.IPv4
tcpf := &conn.TCP
arpf := &conn.ARPv4
tcpSet := tcpf.Set()
var deadline time.Time
START: // START begins search for a new TCP connection.
for {
err = conn.Reset()
if err != nil {
errhandler(err)
}
err = conn.Decode()
if err != nil && !lax.IsEOF(err) {
errhandler(err)
continue START
}
if eth.EtherType() == grams.EtherTypeARP && bytes.Equal(arpf.ProtoTarget(), IPAddr) {
// ARP Packet control.
_log("=======etherType ARPv4")
err = conn.SendResponse()
if err != nil {
errhandler(err)
continue START
}
count++
} else if eth.EtherType() == grams.EtherTypeIPv4 {
// TCP Packet control
if !bytes.Equal(ipf.Destination(), IPAddr) || !bytes.Equal(eth.Destination(), mac) || // check destination address is ours
!tcpf.HasFlags(grams.TCPHEADER_FLAG_SYN) { // Must be SYN packet to start TCP handshake
continue START
}
// Create deadline for TCP transaction finish
deadline = time.Now().Add(timeout)
_log("\n=======ipv4 dst here")
// conn takes care of SYN response. Rest of logic is inside HTTPServer
// TODO standarize where logic lives HTTPServer vs. tcpCtl
err = conn.SendResponse()
if err != nil {
errhandler(err)
continue START
}
SEQ, ACK = tcpf.Seq(), tcpf.Ack()-1
_log("\n=======loop http decode")
// while not the packet we are looking for keep going.
for tcpf.Seq() != SEQ+1 || len(httpf.URL) == 0 || httpf.Method == httpUNDEFINED || tcpf.HasFlags(grams.TCPHEADER_FLAG_SYN) || tcpf.Flags() == grams.TCPHEADER_FLAG_ACK {
// Get incoming ACK and skip it (len=0) and get HTTP request
err = conn.Decode()
if err != nil && !lax.IsEOF(err) || time.Since(deadline) > 0 {
errhandler(err)
continue START
}
_log(lax.Strcat("[ACK] loop expecting ", lax.U32toa(SEQ+1), " got ", lax.U32toa(tcpf.Seq())))
spinLoopContent()
}
lax.LogStringer("HTTP:", httpf)
// Send TCP ACK first and save response
{
response = handler(httpf.URL)
serverHTTPLen = uint32(len(response))
clientHTTPLen = uint32(ipf.TotalLength()) - 20 - uint32(tcpf.Offset())*4
if clientHTTPLen <= 0 {
_log("got a zero length HTTP packet")
continue START
}
httpf.Body = nil
tcpSet.Ack(ACK + clientHTTPLen + 1)
tcpSet.Seq(SEQ + 1)
tcpSet.Flags(grams.TCPHEADER_FLAG_ACK)
err = conn.SendResponse()
if err != nil {
errhandler(err)
continue START
}
}
// Send FIN|PSH|ACK with HTTP response to client
{
tcpf.Set().Flags(grams.TCPHEADER_FLAG_FIN | grams.TCPHEADER_FLAG_PSH | grams.TCPHEADER_FLAG_ACK)
httpf.Body = response
err = conn.SendResponse()
httpf.Reset()
if err != nil {
errhandler(err)
continue START
}
}
// clear current flags to prevent false positive. We seek to ACK the FIN|ACK segment.
tcpSet.ClearFlags(grams.TCPHEADER_FLAG_FIN)
for tcpf.Seq() != SEQ+serverHTTPLen+2 || tcpf.Flags() != grams.TCPHEADER_FLAG_FIN|grams.TCPHEADER_FLAG_ACK {
err = conn.Decode()
if err != nil && !lax.IsEOF(err) || time.Since(deadline) > 0 {
errhandler(err)
continue START
}
_log(lax.Strcat("[FIN] loop expecting seq ", lax.U32toa(SEQ+serverHTTPLen+2), " got ", lax.U32toa(tcpf.Seq()), "\n"))
spinLoopContent()
}
tcpSet.Flags(grams.TCPHEADER_FLAG_ACK)
tcpSet.Ack(ACK + clientHTTPLen + 2)
tcpSet.Seq(SEQ + serverHTTPLen + 2)
err = conn.SendResponse()
if err != nil {
errhandler(err)
}
lax.LogStringer("\nEnd TCP handshake with :", tcpf)
count++
}
spinLoopContent()
}
}
func spinLoopContent() {
}