1/* 2** Zabbix 3** Copyright (C) 2001-2021 Zabbix SIA 4** 5** This program is free software; you can redistribute it and/or modify 6** it under the terms of the GNU General Public License as published by 7** the Free Software Foundation; either version 2 of the License, or 8** (at your option) any later version. 9** 10** This program is distributed in the hope that it will be useful, 11** but WITHOUT ANY WARRANTY; without even the implied warranty of 12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13** GNU General Public License for more details. 14** 15** You should have received a copy of the GNU General Public License 16** along with this program; if not, write to the Free Software 17** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18**/ 19package webpage 20 21import ( 22 "bufio" 23 "fmt" 24 "net/url" 25 "regexp" 26 "strconv" 27 "strings" 28 "time" 29 30 "zabbix.com/internal/agent" 31 "zabbix.com/pkg/conf" 32 "zabbix.com/pkg/plugin" 33 "zabbix.com/pkg/web" 34 "zabbix.com/pkg/zbxregexp" 35) 36 37type Options struct { 38 Timeout int `conf:"optional,range=1:30"` 39} 40 41type Plugin struct { 42 plugin.Base 43 options Options 44} 45 46var impl Plugin 47 48func (p *Plugin) Configure(global *plugin.GlobalOptions, options interface{}) { 49 if err := conf.Unmarshal(options, &p.options); err != nil { 50 p.Warningf("cannot unmarshal configuration options: %s", err) 51 } 52 if p.options.Timeout == 0 { 53 p.options.Timeout = global.Timeout 54 } 55} 56 57func (p *Plugin) Validate(options interface{}) error { 58 var o Options 59 return conf.Unmarshal(options, &o) 60} 61 62func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (interface{}, error) { 63 if len(params) == 0 || params[0] == "" { 64 return nil, fmt.Errorf("Invalid first parameter.") 65 } 66 67 u, err := url.Parse(params[0]) 68 if err != nil { 69 return nil, fmt.Errorf("Cannot parse url: %s", err) 70 } 71 72 if u.Scheme == "" || u.Opaque != "" { 73 params[0] = "http://" + params[0] 74 } 75 76 if len(params) > 2 && params[2] != "" { 77 params[0] += ":" + params[2] 78 } 79 80 if len(params) > 1 && params[1] != "" { 81 if params[1][0] != '/' { 82 params[0] += "/" 83 } 84 85 params[0] += params[1] 86 } 87 88 switch key { 89 case "web.page.regexp": 90 var length *int 91 var output string 92 93 if len(params) > 6 { 94 return nil, fmt.Errorf("Too many parameters.") 95 } 96 97 if len(params) < 4 { 98 return nil, fmt.Errorf("Invalid number of parameters.") 99 } 100 101 rx, err := regexp.Compile(params[3]) 102 if err != nil { 103 return nil, fmt.Errorf("Invalid forth parameter: %s", err) 104 } 105 106 if len(params) > 4 && params[4] != "" { 107 if n, err := strconv.Atoi(params[4]); err != nil { 108 return nil, fmt.Errorf("Invalid fifth parameter: %s", err) 109 } else { 110 length = &n 111 } 112 } 113 114 if len(params) > 5 && params[5] != "" { 115 output = params[5] 116 } else { 117 output = "\\0" 118 } 119 120 s, err := web.Get(params[0], time.Duration(p.options.Timeout)*time.Second, true) 121 if err != nil { 122 return nil, err 123 } 124 125 scanner := bufio.NewScanner(strings.NewReader(s)) 126 for scanner.Scan() { 127 if out, ok := zbxregexp.ExecuteRegex(scanner.Bytes(), rx, []byte(output)); ok { 128 if length != nil { 129 out = agent.CutAfterN(out, *length) 130 } 131 return out, nil 132 } 133 } 134 135 return "", nil 136 case "web.page.perf": 137 if len(params) > 3 { 138 return nil, fmt.Errorf("Too many parameters.") 139 } 140 141 start := time.Now() 142 143 _, err := web.Get(params[0], time.Duration(p.options.Timeout)*time.Second, false) 144 if err != nil { 145 return nil, err 146 } 147 148 return time.Since(start).Seconds(), nil 149 default: 150 if len(params) > 3 { 151 return nil, fmt.Errorf("Too many parameters.") 152 } 153 154 return web.Get(params[0], time.Duration(p.options.Timeout)*time.Second, true) 155 } 156 157} 158 159func init() { 160 plugin.RegisterMetrics(&impl, "WebPage", 161 "web.page.get", "Get content of a web page.", 162 "web.page.perf", "Loading time of full web page (in seconds).", 163 "web.page.regexp", "Find string on a web page.") 164} 165