github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zhttp/utils.go (about)

     1  package zhttp
     2  
     3  import (
     4  	"net/http"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	"golang.org/x/net/html"
    10  
    11  	"github.com/sohaha/zlsgo/zfile"
    12  	"github.com/sohaha/zlsgo/zstring"
    13  )
    14  
    15  type (
    16  	selector struct {
    17  		Attr    map[string]string
    18  		Name    string
    19  		i       int
    20  		Child   bool
    21  		Brother bool
    22  	}
    23  )
    24  
    25  func (s *selector) appendAttr(key, val string, index int) {
    26  	if key == "" {
    27  		s.Name = val[s.i:index]
    28  	} else {
    29  		val = val[s.i:index]
    30  		if v, ok := s.Attr[key]; ok && v != "" {
    31  			s.Attr[key] = s.Attr[key] + " " + val
    32  		} else {
    33  			s.Attr[key] = val
    34  		}
    35  	}
    36  	s.i = index + 1
    37  }
    38  
    39  // ConvertCookie Parse Cookie String
    40  func ConvertCookie(cookiesRaw string) map[string]*http.Cookie {
    41  	cookie := map[string]*http.Cookie{}
    42  	c := strings.Split(cookiesRaw, ";")
    43  	for _, s := range c {
    44  		v := strings.Split(zstring.TrimSpace(s), "=")
    45  		if len(v) == 2 {
    46  			name := zstring.TrimSpace(v[0])
    47  			cookie[name] = &http.Cookie{Name: name, Value: v[1]}
    48  		}
    49  	}
    50  	return cookie
    51  }
    52  
    53  // BodyJSON make the object be encoded in json format and set it to the request body
    54  func BodyJSON(v interface{}) *bodyJson {
    55  	return &bodyJson{v: v}
    56  }
    57  
    58  // BodyXML make the object be encoded in xml format and set it to the request body
    59  func BodyXML(v interface{}) *bodyXml {
    60  	return &bodyXml{v: v}
    61  }
    62  
    63  func File(path string, field ...string) interface{} {
    64  	var matches []string
    65  	path = zfile.RealPath(path)
    66  	uploads := make([]FileUpload, 0)
    67  	fieldName := "media"
    68  	if len(field) > 0 {
    69  		fieldName = field[0]
    70  	}
    71  	s, err := os.Stat(path)
    72  	if err == nil && !s.IsDir() {
    73  		file, _ := os.Open(path)
    74  		return []FileUpload{{
    75  			File:      file,
    76  			FileName:  filepath.Base(path),
    77  			FieldName: fieldName,
    78  		}}
    79  	}
    80  	m, err := filepath.Glob(path)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	matches = append(matches, m...)
    85  	if len(matches) == 0 {
    86  		return ErrNoMatched
    87  	}
    88  
    89  	for _, match := range matches {
    90  		if s, e := os.Stat(match); e != nil || s.IsDir() {
    91  			continue
    92  		}
    93  		file, _ := os.Open(match)
    94  		uploads = append(uploads, FileUpload{
    95  			File:      file,
    96  			FileName:  filepath.Base(match),
    97  			FieldName: fieldName,
    98  		})
    99  	}
   100  
   101  	return uploads
   102  }
   103  
   104  var UserAgentLists = []string{
   105  	"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
   106  	"Mozilla/5.0 (Linux; U; Android 2.3.6; zh-cn; GT-S5660 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MicroMessenger/4.5.255",
   107  	"Mozilla/5.0 (X11; OpenBSD i386) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36",
   108  	"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1944.0 Safari/537.36",
   109  	"Mozilla/5.0 (Windows NT 5.1) Gecko/20100101 Firefox/14.0 Opera/12.0",
   110  	"Mozilla/5.0 (compatible; Googlebot/2.1;+http://www.google.com/bot.html)",
   111  }
   112  
   113  func RandomUserAgent() Header {
   114  	return Header{"User-Agent": UserAgentLists[zstring.RandInt(0, len(UserAgentLists)-1)]}
   115  }
   116  
   117  func matchElName(n *html.Node, name string) bool {
   118  	return name == "" || name == n.Data
   119  }
   120  
   121  func arr2Attr(args []map[string]string) map[string][]string {
   122  	var attr map[string][]string
   123  	if len(args) > 0 {
   124  		attr = make(map[string][]string, len(args[0]))
   125  		for i := range args[0] {
   126  			attr[i] = strings.Fields(args[0][i])
   127  		}
   128  	}
   129  	return attr
   130  }
   131  
   132  func getAttrValue(attributes []html.Attribute) map[string]string {
   133  	var values = make(map[string]string)
   134  	for i := 0; i < len(attributes); i++ {
   135  		_, exists := values[attributes[i].Key]
   136  		if !exists {
   137  			values[attributes[i].Key] = attributes[i].Val
   138  		}
   139  	}
   140  	return values
   141  }
   142  
   143  func findAttrValue(attr html.Attribute, attribute string, value []string) bool {
   144  	if attr.Key == attribute {
   145  		attr := strings.Fields(attr.Val)
   146  		num := len(value)
   147  		// todo optimization
   148  		for i := range value {
   149  			for a := range attr {
   150  				if attr[a] == value[i] {
   151  					num--
   152  					break
   153  				}
   154  			}
   155  		}
   156  		return num == 0
   157  	}
   158  	return false
   159  }
   160  
   161  func getElText(r QueryHTML, full bool) string {
   162  	b := zstring.Buffer()
   163  	var f func(*html.Node)
   164  	f = func(n *html.Node) {
   165  		if n == nil {
   166  			return
   167  		}
   168  
   169  		if n.Type == html.TextNode {
   170  			b.WriteString(n.Data)
   171  		}
   172  
   173  		if full {
   174  			for i := range r.filter {
   175  				if n == r.filter[i] {
   176  					return
   177  				}
   178  			}
   179  			if matchElName(n, "script") || matchElName(n, "style") {
   180  				return
   181  			}
   182  			if n.Type == html.ElementNode {
   183  				f(n.FirstChild)
   184  			}
   185  		}
   186  
   187  		if n.NextSibling != nil {
   188  			f(n.NextSibling)
   189  		}
   190  	}
   191  	f(r.getNode().FirstChild)
   192  	return b.String()
   193  }
   194  
   195  func forChild(node *html.Node, fn func(n *html.Node) bool) {
   196  	n := node.FirstChild
   197  	for {
   198  		if n == nil {
   199  			return
   200  		}
   201  		if n.Type == html.ElementNode {
   202  			if !fn(n) {
   203  				return
   204  			}
   205  		}
   206  		n = n.NextSibling
   207  	}
   208  }
   209  
   210  func matchEl(n *html.Node, el string, args map[string][]string) *html.Node {
   211  	if n.Type == html.ElementNode && matchElName(n, el) {
   212  		if len(args) > 0 {
   213  			for i := 0; i < len(n.Attr); i++ {
   214  				attr := n.Attr[i]
   215  				for name, val := range args {
   216  					if findAttrValue(attr, name, val) {
   217  						return n
   218  					}
   219  				}
   220  			}
   221  		} else {
   222  			return n
   223  		}
   224  	}
   225  	return nil
   226  }
   227  
   228  func findChild(node *html.Node, el string, args []map[string]string, multiple bool) (elArr []*html.Node) {
   229  	attr := arr2Attr(args)
   230  	n := matchEl(node, el, attr)
   231  	if n != nil {
   232  		elArr = []*html.Node{n}
   233  		if !multiple {
   234  			elArr = []*html.Node{n}
   235  			return
   236  		}
   237  	}
   238  	for c := node.FirstChild; c != nil; c = c.NextSibling {
   239  		p := findChild(c, el, args, multiple)
   240  		elArr = append(elArr, p...)
   241  		if !multiple && len(elArr) > 0 {
   242  			return
   243  		}
   244  	}
   245  
   246  	return
   247  }