mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-02 22:17:49 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8fc9dd0670 | |||
| 479beeeece | |||
| 2526660a96 | |||
| 4213d6f582 | |||
| 81cf507e4e | |||
| 86cc0e31f1 | |||
| e3e95cacfe |
@@ -2,6 +2,8 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -211,3 +213,41 @@ func (c *Client) Post(url, contentType string, body io.Reader) (resp *Response,
|
|||||||
req.Header.Set("Content-Type", contentType)
|
req.Header.Set("Content-Type", contentType)
|
||||||
return c.Do(req)
|
return c.Do(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PostForm issues a POST to the specified URL, with data's keys and
|
||||||
|
// values URL-encoded as the request body.
|
||||||
|
//
|
||||||
|
// The Content-Type header is set to application/x-www-form-urlencoded.
|
||||||
|
// To set other headers, use NewRequest and DefaultClient.Do.
|
||||||
|
//
|
||||||
|
// When err is nil, resp always contains a non-nil resp.Body.
|
||||||
|
// Caller should close resp.Body when done reading from it.
|
||||||
|
//
|
||||||
|
// PostForm is a wrapper around DefaultClient.PostForm.
|
||||||
|
//
|
||||||
|
// See the Client.Do method documentation for details on how redirects
|
||||||
|
// are handled.
|
||||||
|
//
|
||||||
|
// To make a request with a specified context.Context, use NewRequestWithContext
|
||||||
|
// and DefaultClient.Do.
|
||||||
|
func PostForm(url string, data url.Values) (resp *Response, err error) {
|
||||||
|
return DefaultClient.PostForm(url, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostForm issues a POST to the specified URL,
|
||||||
|
// with data's keys and values URL-encoded as the request body.
|
||||||
|
//
|
||||||
|
// The Content-Type header is set to application/x-www-form-urlencoded.
|
||||||
|
// To set other headers, use NewRequest and Client.Do.
|
||||||
|
//
|
||||||
|
// When err is nil, resp always contains a non-nil resp.Body.
|
||||||
|
// Caller should close resp.Body when done reading from it.
|
||||||
|
//
|
||||||
|
// See the Client.Do method documentation for details on how redirects
|
||||||
|
// are handled.
|
||||||
|
//
|
||||||
|
// To make a request with a specified context.Context, use NewRequestWithContext
|
||||||
|
// and Client.Do.
|
||||||
|
func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
|
||||||
|
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
||||||
|
}
|
||||||
|
|||||||
+140
-123
@@ -5,6 +5,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net/textproto"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -25,17 +26,43 @@ func (c *Client) Do(req *Request) (*Response, error) {
|
|||||||
req.AddCookie(cookie)
|
req.AddCookie(cookie)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transport := c.Transport
|
||||||
|
if transport == nil {
|
||||||
|
transport = DefaultTransport
|
||||||
|
}
|
||||||
|
res, err := transport.RoundTrip(req)
|
||||||
|
|
||||||
|
if c.Jar != nil {
|
||||||
|
if rc := res.Cookies(); len(rc) > 0 {
|
||||||
|
c.Jar.SetCookies(req.URL, rc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type Transport struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
var DefaultTransport RoundTripper
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
DefaultTransport = &Transport{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Transport) RoundTrip(req *Request) (*Response, error) {
|
||||||
switch req.URL.Scheme {
|
switch req.URL.Scheme {
|
||||||
case "http":
|
case "http":
|
||||||
return c.doHTTP(req)
|
return t.doHTTP(req)
|
||||||
case "https":
|
case "https":
|
||||||
return c.doHTTPS(req)
|
return t.doHTTPS(req)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid schemer : %s", req.URL.Scheme)
|
return nil, fmt.Errorf("invalid schemer : %s", req.URL.Scheme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) doHTTP(req *Request) (*Response, error) {
|
func (t *Transport) doHTTP(req *Request) (*Response, error) {
|
||||||
// make TCP connection
|
// make TCP connection
|
||||||
ip := net.ParseIP(req.URL.Hostname())
|
ip := net.ParseIP(req.URL.Hostname())
|
||||||
port := 80
|
port := 80
|
||||||
@@ -106,10 +133,10 @@ func (c *Client) doHTTP(req *Request) (*Response, error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.doResp(conn, req)
|
return t.doResp(conn, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) doHTTPS(req *Request) (*Response, error) {
|
func (t *Transport) doHTTPS(req *Request) (*Response, error) {
|
||||||
conn, err := tls.Dial("tcp", req.URL.Host, nil)
|
conn, err := tls.Dial("tcp", req.URL.Host, nil)
|
||||||
retry := 0
|
retry := 0
|
||||||
for ; err != nil; conn, err = tls.Dial("tcp", req.URL.Host, nil) {
|
for ; err != nil; conn, err = tls.Dial("tcp", req.URL.Host, nil) {
|
||||||
@@ -167,141 +194,131 @@ func (c *Client) doHTTPS(req *Request) (*Response, error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.doResp(conn, req)
|
return t.doResp(conn, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) doResp(conn net.Conn, req *Request) (*Response, error) {
|
func (t *Transport) doResp(conn net.Conn, req *Request) (*Response, error) {
|
||||||
resp := &Response{
|
resp := &Response{
|
||||||
Header: map[string][]string{},
|
Header: map[string][]string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header
|
br := bufio.NewReader(conn)
|
||||||
var scanner *bufio.Scanner
|
tp := textproto.NewReader(br)
|
||||||
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 {
|
|
||||||
// Take care of the case where "\r\n\r\n" is on the boundary of a buffer
|
|
||||||
start := ofs
|
|
||||||
if start > 3 {
|
|
||||||
start -= 3
|
|
||||||
}
|
|
||||||
idx := bytes.Index(buf[start:ofs+n], []byte("\r\n\r\n"))
|
|
||||||
if idx == -1 {
|
|
||||||
ofs += n
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
idx += start + 4
|
|
||||||
|
|
||||||
scanner = bufio.NewScanner(bytes.NewReader(buf[0 : ofs+n]))
|
for {
|
||||||
if resp.Status == "" && scanner.Scan() {
|
line, err := tp.ReadLine()
|
||||||
status := strings.SplitN(scanner.Text(), " ", 2)
|
if err != nil {
|
||||||
if len(status) != 2 {
|
if err == io.ErrNoProgress {
|
||||||
conn.Close()
|
// default: no timeout
|
||||||
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 strings.ToLower(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 err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if n == 0 {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
status := strings.SplitN(line, " ", 2)
|
||||||
|
if len(status) != 2 {
|
||||||
|
conn.Close()
|
||||||
|
return nil, fmt.Errorf("invalid status : %q", line)
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
m, err := tp.ReadMIMEHeader()
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for k, v := range m {
|
||||||
|
//fmt.Printf("%s: %s\n", k, v)
|
||||||
|
|
||||||
|
if strings.ToLower(k) == "content-length" {
|
||||||
|
resp.ContentLength, err = strconv.ParseInt(v[0], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil, err
|
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 resp.Header.Get(k) == "" {
|
||||||
|
resp.Header.Set(k, v[0])
|
||||||
|
v = v[1:]
|
||||||
|
}
|
||||||
|
for _, vv := range v {
|
||||||
|
resp.Header.Add(k, vv)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Jar != nil {
|
if resp.Header.Get("Transfer-Encoding") == "chunked" {
|
||||||
if rc := resp.Cookies(); len(rc) > 0 {
|
// chunked
|
||||||
c.Jar.SetCookies(req.URL, rc)
|
cur := 0
|
||||||
|
end := 0
|
||||||
|
for {
|
||||||
|
length := 0
|
||||||
|
if len(buf) < cur+6 {
|
||||||
|
// This is not a very accurate check, but in many cases it should be fine.
|
||||||
|
return nil, fmt.Errorf("slice out of range : use http.SetBuf() to change the allocation to %d bytes or more", cur+6)
|
||||||
|
}
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
buf[cur+i], err = br.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
length = i + 1
|
||||||
|
if i > 1 && buf[cur+i-1] == '\r' && buf[cur+i] == '\n' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//fmt.Printf("cur:%d length:%d\n", cur, length)
|
||||||
|
|
||||||
|
size, err := strconv.ParseInt(string(buf[cur:cur+length-2]), 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//cur += length
|
||||||
|
//fmt.Printf("cur:%d length:%d size:%d\n", cur, length, size)
|
||||||
|
|
||||||
|
end = cur + int(size) + 2 // size + 2 (\r\n)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
for i := 0; i < int(size)+2; i++ {
|
||||||
|
buf[cur+i], err = br.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur += int(size)
|
||||||
|
|
||||||
|
if size == 0 {
|
||||||
|
end = end - 2
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
//fmt.Printf("%q\n", buf[:end])
|
||||||
|
resp.Body = io.NopCloser(bytes.NewReader(buf[:end]))
|
||||||
|
} else {
|
||||||
|
end := int(resp.ContentLength)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
for i := 0; i < end; i++ {
|
||||||
|
buf[i], err = br.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp.Body = io.NopCloser(bytes.NewReader(buf[:end]))
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp, conn.Close()
|
return resp, conn.Close()
|
||||||
|
|||||||
@@ -71,10 +71,13 @@ func (d *Driver) ConnectTCPSocket(addr, port string) error {
|
|||||||
name[6] = byte(ipaddr[2])
|
name[6] = byte(ipaddr[2])
|
||||||
name[7] = byte(ipaddr[3])
|
name[7] = byte(ipaddr[3])
|
||||||
|
|
||||||
_, err = d.Rpc_lwip_connect(socket, name, uint32(len(name)))
|
result, err := d.Rpc_lwip_connect(socket, name, uint32(len(name)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if result == -1 {
|
||||||
|
return fmt.Errorf("failed to connect to %d.%d.%d.%d port %s", addr[0], addr[1], addr[2], addr[3], port)
|
||||||
|
}
|
||||||
|
|
||||||
readset := []byte{}
|
readset := []byte{}
|
||||||
writeset := []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
writeset := []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||||
@@ -341,8 +344,11 @@ func (d *Driver) ReadSocket(b []byte) (n int, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if nn < 0 {
|
if nn == -76 {
|
||||||
return 0, fmt.Errorf("error %d", n)
|
// no data
|
||||||
|
return 0, nil
|
||||||
|
} else if nn < 0 {
|
||||||
|
return 0, fmt.Errorf("error %d", nn)
|
||||||
} else if nn == 0 || nn == -30848 {
|
} else if nn == 0 || nn == -30848 {
|
||||||
return 0, d.DisconnectSocket()
|
return 0, d.DisconnectSocket()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user