package elasticsearch import ( "bufio" "encoding/json" "strconv" "strings" osm "git.loafle.net/overflow/service_matcher-go" ) type ElasticSearchMatcher struct { osm.Matchers } func (m *ElasticSearchMatcher) Key() string { return "ELASTICSEARCH" } func (m *ElasticSearchMatcher) Name(matchCtx *osm.MatchCtx) string { name := "ElasticSearch" if v, ok := matchCtx.GetAttribute("number"); ok { name = name + " (" + v.(string) + ")" } return name } func (m *ElasticSearchMatcher) IsPrePacket(matchCtx *osm.MatchCtx) bool { return false } func (m *ElasticSearchMatcher) HasResponse(matchCtx *osm.MatchCtx, index int) bool { return true } func (m *ElasticSearchMatcher) IsError(matchCtx *osm.MatchCtx, index int, packet *osm.Packet) bool { return false } func (m *ElasticSearchMatcher) Match(matchCtx *osm.MatchCtx, index int, packet *osm.Packet) error { if packet == nil || !packet.Valid() { return osm.NoPacketReceivedError() } str := string(packet.Bytes()) 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 osm.NotMatchedError() } if strings.Contains(line, ":") { kv := strings.Split(line, ": ") if kv[0] == "content-type" && !strings.Contains(kv[1], "application/json") { return osm.NotMatchedError() } if kv[0] == "content-length" { len, err := strconv.Atoi(kv[1]) if err != nil { return osm.NotMatchedError() } contentLen = len } } lineNo++ } content := body[:contentLen] if strings.HasPrefix(content, "{") && strings.HasSuffix(content, "}") { return osm.NotMatchedError() } m.parseJson(matchCtx, content) if _, ok := matchCtx.GetAttribute("cluster_name"); !ok { return osm.NotMatchedError() } if _, ok := matchCtx.GetAttribute("cluster_uuid"); !ok { return osm.NotMatchedError() } return nil } func (m *ElasticSearchMatcher) parseJson(matchCtx *osm.MatchCtx, jsonstr string) error { jsonMap := make(map[string]interface{}) err := json.Unmarshal([]byte(jsonstr), &jsonMap) if err != nil { return err } m.dumpMap(matchCtx, jsonMap) return nil } func (m *ElasticSearchMatcher) dumpMap(matchCtx *osm.MatchCtx, jsonMap map[string]interface{}) { for k, v := range jsonMap { if mv, ok := v.(map[string]interface{}); ok { m.dumpMap(matchCtx, mv) } else { s, ok := v.(string) if ok { matchCtx.SetAttribute(k, s) } } } } func NewMatcher() osm.Matcher { m := &ElasticSearchMatcher{} reqStr := "GET / HTTP/1.1\r\n\r\n" byte := make([]byte, len(reqStr)) copy(byte[:], reqStr) m.AddPacket(osm.NewPacket(byte, len(reqStr))) return m }