mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-14 11:53:41 +00:00
rtl8720dn: add support for http.Get(), http.Post() and cookie
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net"
|
||||
"tinygo.org/x/drivers/net/tls"
|
||||
)
|
||||
|
||||
var buf []byte
|
||||
|
||||
func SetBuf(b []byte) {
|
||||
buf = b
|
||||
}
|
||||
|
||||
func (c *Client) Do(req *Request) (*Response, error) {
|
||||
switch req.URL.Scheme {
|
||||
case "http":
|
||||
return c.doHTTP(req)
|
||||
case "https":
|
||||
return c.doHTTPS(req)
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid schemer : %s", req.URL.Scheme)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) doHTTP(req *Request) (*Response, error) {
|
||||
if c.Jar != nil {
|
||||
for _, cookie := range c.Jar.Cookies(req.URL) {
|
||||
req.AddCookie(cookie)
|
||||
}
|
||||
}
|
||||
|
||||
// make TCP connection
|
||||
ip := net.ParseIP(req.URL.Host)
|
||||
raddr := &net.TCPAddr{IP: ip, Port: 80}
|
||||
laddr := &net.TCPAddr{Port: 8080}
|
||||
|
||||
conn, err := net.DialTCP("tcp", laddr, raddr)
|
||||
retry := 0
|
||||
for ; err != nil; conn, err = net.DialTCP("tcp", laddr, raddr) {
|
||||
retry++
|
||||
if retry > 10 {
|
||||
return nil, fmt.Errorf("Connection failed: %s", err.Error())
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
p := req.URL.Path
|
||||
if p == "" {
|
||||
p = "/"
|
||||
}
|
||||
fmt.Fprintln(conn, req.Method+" "+p+" HTTP/1.1")
|
||||
fmt.Fprintln(conn, "Host:", req.URL.Host)
|
||||
|
||||
if req.Header.get(`User-Agent`) == "" {
|
||||
fmt.Fprintln(conn, "User-Agent: TinyGo")
|
||||
}
|
||||
|
||||
for k, v := range req.Header {
|
||||
if v == nil || len(v) == 0 {
|
||||
return nil, fmt.Errorf("req.Header error: %s", k)
|
||||
}
|
||||
fmt.Fprintln(conn, k+": "+v[0])
|
||||
}
|
||||
|
||||
if req.Header.get(`Connection`) == "" {
|
||||
fmt.Fprintln(conn, "Connection: close")
|
||||
}
|
||||
|
||||
if req.ContentLength > 0 {
|
||||
fmt.Fprintf(conn, "Content-Length: %d\n", req.ContentLength)
|
||||
}
|
||||
|
||||
fmt.Fprintln(conn)
|
||||
|
||||
if req.ContentLength > 0 {
|
||||
b, err := req.GetBody()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err := b.Read(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn.Write(buf[:n])
|
||||
|
||||
b.Close()
|
||||
|
||||
}
|
||||
|
||||
return c.doResp(conn, req)
|
||||
}
|
||||
|
||||
func (c *Client) doHTTPS(req *Request) (*Response, error) {
|
||||
conn, err := tls.Dial("tcp", req.URL.Host, nil)
|
||||
retry := 0
|
||||
for ; err != nil; conn, err = tls.Dial("tcp", req.URL.Host, nil) {
|
||||
retry++
|
||||
if retry > 10 {
|
||||
return nil, fmt.Errorf("Connection failed: %s", err.Error())
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
p := req.URL.Path
|
||||
if p == "" {
|
||||
p = "/"
|
||||
}
|
||||
fmt.Fprintln(conn, req.Method+" "+p+" HTTP/1.1")
|
||||
fmt.Fprintln(conn, "Host:", req.URL.Host)
|
||||
|
||||
if req.Header.get(`User-Agent`) == "" {
|
||||
fmt.Fprintln(conn, "User-Agent: TinyGo")
|
||||
}
|
||||
|
||||
for k, v := range req.Header {
|
||||
if v == nil || len(v) == 0 {
|
||||
return nil, fmt.Errorf("req.Header error: %s", k)
|
||||
}
|
||||
fmt.Fprintln(conn, k+": "+v[0])
|
||||
}
|
||||
|
||||
if req.Header.get(`Connection`) == "" {
|
||||
fmt.Fprintln(conn, "Connection: close")
|
||||
}
|
||||
|
||||
if req.ContentLength > 0 {
|
||||
fmt.Fprintf(conn, "Content-Length: %d\n", req.ContentLength)
|
||||
}
|
||||
|
||||
fmt.Fprintln(conn)
|
||||
|
||||
if req.ContentLength > 0 {
|
||||
b, err := req.GetBody()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err := b.Read(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn.Write(buf[:n])
|
||||
|
||||
b.Close()
|
||||
|
||||
}
|
||||
|
||||
return c.doResp(conn, req)
|
||||
}
|
||||
|
||||
func (c *Client) doResp(conn net.Conn, req *Request) (*Response, error) {
|
||||
resp := &Response{
|
||||
Header: map[string][]string{},
|
||||
}
|
||||
|
||||
// Header
|
||||
var scanner *bufio.Scanner
|
||||
cont := true
|
||||
ofs := 0
|
||||
remain := int64(0)
|
||||
for cont {
|
||||
for n, err := conn.Read(buf[ofs:]); n > 0; n, err = conn.Read(buf[ofs:]) {
|
||||
if err != nil {
|
||||
println("Read error: " + err.Error())
|
||||
} else {
|
||||
idx := bytes.Index(buf[ofs:ofs+n], []byte("\r\n\r\n"))
|
||||
if idx == -1 {
|
||||
ofs += n
|
||||
continue
|
||||
}
|
||||
idx += ofs + 4
|
||||
|
||||
scanner = bufio.NewScanner(bytes.NewReader(buf[0 : ofs+n]))
|
||||
if resp.Status == "" && scanner.Scan() {
|
||||
status := strings.SplitN(scanner.Text(), " ", 2)
|
||||
if len(status) != 2 {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("invalid status : %q", scanner.Text())
|
||||
}
|
||||
resp.Proto = status[0]
|
||||
fmt.Sscanf(status[0], "HTTP/%d.%d", &resp.ProtoMajor, &resp.ProtoMinor)
|
||||
|
||||
resp.Status = status[1]
|
||||
fmt.Sscanf(status[1], "%d", &resp.StatusCode)
|
||||
}
|
||||
|
||||
for scanner.Scan() {
|
||||
text := scanner.Text()
|
||||
if text == "" {
|
||||
// end of header
|
||||
if idx < n+ofs {
|
||||
ofs = ofs + n - idx
|
||||
for i := 0; i < ofs; i++ {
|
||||
buf[i] = buf[i+idx]
|
||||
}
|
||||
} else {
|
||||
ofs = 0
|
||||
}
|
||||
break
|
||||
} else {
|
||||
header := strings.SplitN(text, ": ", 2)
|
||||
if len(header) != 2 {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("invalid header : %q", text)
|
||||
}
|
||||
if resp.Header.Get(header[0]) == "" {
|
||||
resp.Header.Set(header[0], header[1])
|
||||
} else {
|
||||
resp.Header.Add(header[0], header[1])
|
||||
}
|
||||
|
||||
if header[0] == "Content-Length" {
|
||||
resp.ContentLength, err = strconv.ParseInt(header[1], 10, 64)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
remain = resp.ContentLength
|
||||
}
|
||||
}
|
||||
}
|
||||
cont = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Body
|
||||
remain -= int64(ofs)
|
||||
if remain <= 0 {
|
||||
resp.Body = io.NopCloser(bytes.NewReader(buf[:ofs]))
|
||||
if c.Jar != nil {
|
||||
if rc := resp.Cookies(); len(rc) > 0 {
|
||||
c.Jar.SetCookies(req.URL, rc)
|
||||
}
|
||||
}
|
||||
return resp, conn.Close()
|
||||
}
|
||||
|
||||
cont = true
|
||||
lastRequestTime := time.Now()
|
||||
for cont {
|
||||
for {
|
||||
end := ofs + 0x400
|
||||
if len(buf) < end {
|
||||
return nil, fmt.Errorf("slice out of range : use http.SetBuf() to change the allocation to %d bytes or more", end)
|
||||
}
|
||||
n, err := conn.Read(buf[ofs : ofs+0x400])
|
||||
if n == 0 {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
} else {
|
||||
ofs += n
|
||||
remain -= int64(n)
|
||||
if remain <= 0 {
|
||||
resp.Body = io.NopCloser(bytes.NewReader(buf[:ofs]))
|
||||
cont = false
|
||||
break
|
||||
}
|
||||
if time.Now().Sub(lastRequestTime).Milliseconds() >= 1000 {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("time out")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if c.Jar != nil {
|
||||
if rc := resp.Cookies(); len(rc) > 0 {
|
||||
c.Jar.SetCookies(req.URL, rc)
|
||||
}
|
||||
}
|
||||
|
||||
return resp, conn.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user