ходим на сайты в интернете
This commit is contained in:
+73
-26
@@ -2,15 +2,22 @@ package http
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Do(method string, url string) (*Response, error) {
|
||||
var (
|
||||
CRLF = []byte("\r\n")
|
||||
SP = []byte(" ")
|
||||
)
|
||||
|
||||
func Do(method string, url string, headers []*Header) (*Response, error) {
|
||||
url = strings.TrimPrefix(url, "http://")
|
||||
url = strings.TrimPrefix(url, "https://")
|
||||
path := "/"
|
||||
arr := strings.Split(url, "/")
|
||||
if len(arr) == 2 {
|
||||
@@ -20,56 +27,93 @@ func Do(method string, url string) (*Response, error) {
|
||||
path = "/" + path
|
||||
}
|
||||
|
||||
conn, err := net.Dial("tcp", arr[0])
|
||||
connectPath := arr[0]
|
||||
// conn, err := net.Dial("tcp", connectPath)
|
||||
conn, err := tls.Dial("tcp", connectPath, nil)
|
||||
if err != nil {
|
||||
return nil, errors.New("connect " + arr[0])
|
||||
return nil, errors.New("connect " + connectPath)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
WriteRequest(conn, method, path, "HTTP/1.0")
|
||||
WriteRequest(conn, method, arr[0], path, "HTTP/1.0", headers)
|
||||
return ReadResponse(conn)
|
||||
}
|
||||
|
||||
func WriteRequest(w io.Writer, method string, path string, httpVersion string) {
|
||||
fmt.Fprintf(w, "%s %s %s\r\n\r\n", method, path, httpVersion)
|
||||
func WriteRequest(
|
||||
w io.Writer,
|
||||
method string,
|
||||
host string,
|
||||
path string,
|
||||
httpVersion string,
|
||||
headers []*Header,
|
||||
) {
|
||||
io.WriteString(w, method)
|
||||
w.Write(SP)
|
||||
io.WriteString(w, path)
|
||||
w.Write(SP)
|
||||
io.WriteString(w, httpVersion)
|
||||
w.Write(CRLF)
|
||||
|
||||
for _, header := range headers {
|
||||
WriteHeader(w, header.Name, header.Value)
|
||||
}
|
||||
|
||||
// headers end
|
||||
w.Write(CRLF)
|
||||
|
||||
// todo: body
|
||||
}
|
||||
|
||||
func WriteHeader(w io.Writer, name string, value string) {
|
||||
fmt.Fprintf(w, "%s:%s", name, value)
|
||||
w.Write(CRLF)
|
||||
}
|
||||
|
||||
func ReadResponse(r io.Reader) (*Response, error) {
|
||||
response := &Response{}
|
||||
|
||||
b := bufio.NewReader(r)
|
||||
|
||||
status, err := b.ReadString('\n')
|
||||
if err != nil {
|
||||
return response, errors.New("read status")
|
||||
if _, err := b.ReadString(' '); err != nil {
|
||||
return nil, errors.New("read httpVersion")
|
||||
}
|
||||
arr := strings.Split(status, " ")
|
||||
response.StatusCode, err = strconv.Atoi(arr[1])
|
||||
statusCodeStr, err := b.ReadString(' ')
|
||||
if err != nil {
|
||||
return response, errors.New("read status code")
|
||||
return nil, errors.New("read statusCode")
|
||||
}
|
||||
if _, err := b.ReadString('\r'); err != nil {
|
||||
return nil, errors.New("read statusName")
|
||||
}
|
||||
if _, err := b.ReadString('\n'); err != nil {
|
||||
return nil, errors.New("read LF")
|
||||
}
|
||||
|
||||
statusCode, err := strconv.Atoi(statusCodeStr[:len(statusCodeStr)-1])
|
||||
if err != nil {
|
||||
return nil, errors.New("read statusCode")
|
||||
}
|
||||
|
||||
headerStr := ""
|
||||
contentLengthStr := ""
|
||||
headers := []*Header{}
|
||||
for {
|
||||
headerStr, err = b.ReadString('\n')
|
||||
if err != nil {
|
||||
return response, errors.New("read header")
|
||||
return nil, errors.New("read header")
|
||||
}
|
||||
if headerStr == "\r\n" {
|
||||
break
|
||||
}
|
||||
arr := strings.Split(headerStr, ": ")
|
||||
value := strings.TrimSpace(arr[1])
|
||||
response.Headers = append(response.Headers, &Header{Name: arr[0], Value: value})
|
||||
header := &Header{Name: arr[0], Value: value}
|
||||
if header.Name == "Content-Length" {
|
||||
contentLengthStr = header.Value
|
||||
}
|
||||
headers = append(headers, header)
|
||||
}
|
||||
|
||||
contentTypeHeader, err := response.GetHeader("Content-Length")
|
||||
length, err := strconv.Atoi(contentLengthStr)
|
||||
if err != nil {
|
||||
return response, errors.New("get Content-Length")
|
||||
}
|
||||
length, err := strconv.Atoi(contentTypeHeader.Value)
|
||||
if err != nil {
|
||||
return response, errors.New("read Content-Length")
|
||||
return nil, errors.New("read Content-Length")
|
||||
}
|
||||
|
||||
body := make([]byte, 0, length)
|
||||
@@ -77,11 +121,14 @@ func ReadResponse(r io.Reader) (*Response, error) {
|
||||
for i := 0; i < length; i++ {
|
||||
r, err := b.ReadByte()
|
||||
if err != nil {
|
||||
return response, errors.New("read body")
|
||||
return nil, errors.New("read body")
|
||||
}
|
||||
body = append(body, r)
|
||||
}
|
||||
response.Body = body
|
||||
|
||||
return response, nil
|
||||
return &Response{
|
||||
StatusCode: statusCode,
|
||||
Headers: headers,
|
||||
Body: body,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user