package elasticsearch import ( "bufio" "encoding/json" "strconv" "strings" csm "git.loafle.net/commons/service_matcher-go" ) type ElasticSearchMatcher struct { csm.Matchers meta csm.Metadata } func (es *ElasticSearchMatcher) Key() string { return "ElasticSearch" } func (es *ElasticSearchMatcher) Name() string { name := "ElasticSearch" if v, ok := es.meta["number"]; ok { name = name + " (" + v + ")" } return name } func (es *ElasticSearchMatcher) Meta() csm.Metadata { return es.meta } func (es *ElasticSearchMatcher) IsPrePacket() bool { return false } func (es *ElasticSearchMatcher) HasResponse(index int) bool { return true } func (es *ElasticSearchMatcher) IsError(info csm.MatchInfo, index int, packet *csm.Packet) bool { return false } func (es *ElasticSearchMatcher) Match(info csm.MatchInfo, index int, packet *csm.Packet) error { if packet == nil || packet.Buffer == nil || packet.Len == 0 { return csm.NoPacketReceivedError() } str := string(packet.Buffer) hnb := strings.Split(str, "\r\n\r\n") header := hnb[0] body := hnb[1] lineNo := 0 scanner := bufio.NewScanner(strings.NewReader(header)) contentLen := 0 for scanner.Scan() { line := scanner.Text() if strings.Compare(line, "") == 0 { continue } if lineNo == 0 && !strings.HasPrefix(line, "HTTP/") { return csm.NotMatchedError() } if strings.Contains(line, ":") { kv := strings.Split(line, ": ") if kv[0] == "content-type" && !strings.Contains(kv[1], "application/json") { return csm.NotMatchedError() } if kv[0] == "content-length" { len, err := strconv.Atoi(kv[1]) if err != nil { return csm.NotMatchedError() } contentLen = len } } lineNo++ } content := body[:contentLen] if strings.HasPrefix(content, "{") && strings.HasSuffix(content, "}") { return csm.NotMatchedError() } es.parseJson(content) if _, ok := es.meta["cluster_name"]; !ok { return csm.NotMatchedError() } if _, ok := es.meta["cluster_uuid"]; !ok { return csm.NotMatchedError() } return nil } func (es *ElasticSearchMatcher) parseJson(jsonstr string) error { jsonMap := make(map[string]interface{}) err := json.Unmarshal([]byte(jsonstr), &jsonMap) if err != nil { return err } es.dumpMap(jsonMap) return nil } func (es *ElasticSearchMatcher) dumpMap(m map[string]interface{}) { for k, v := range m { if mv, ok := v.(map[string]interface{}); ok { es.dumpMap(mv) } else { s, ok := v.(string) if ok { es.meta[k] = s } } } } func NewMatcher() csm.Matcher { m := &ElasticSearchMatcher{} m.meta = csm.NewMetadata() reqStr := "GET / HTTP/1.1\r\n\r\n" byte := make([]byte, len(reqStr)) copy(byte[:], reqStr) m.AddPacket(csm.NewPacket(byte, len(reqStr))) return m }