package elasticsearch import ( "bufio" "encoding/json" "strconv" "strings" osm "git.loafle.net/overflow/service_matcher-go" ) type ElasticSearchMatcher struct { osm.Matchers meta osm.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() osm.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 osm.MatchInfo, index int, packet *osm.Packet) bool { return false } func (es *ElasticSearchMatcher) Match(info osm.MatchInfo, index int, packet *osm.Packet) error { if packet == nil || packet.Buffer == nil || packet.Len == 0 { return osm.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 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() } es.parseJson(content) if _, ok := es.meta["cluster_name"]; !ok { return osm.NotMatchedError() } if _, ok := es.meta["cluster_uuid"]; !ok { return osm.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() osm.Matcher { m := &ElasticSearchMatcher{} m.meta = osm.NewMetadata() 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 }