package nginx import ( "bufio" "regexp" "strings" "unicode" ) func (c *NgxConfig) parseServer(scanner *bufio.Scanner) { server := NewNgxServer() for scanner.Scan() { d := parseDirective(scanner) switch d.Directive { case Location: server.parseLocation(d.Params) case CommentStart: server.commentQueue.Enqueue(d.Params) default: server.parseDirective(d) } } // Attach the rest of the comments to the last location if len(server.Locations) > 0 { server.Locations[len(server.Locations)-1].Comments += server.commentQueue.DequeueAllComments() } // Attach comments which are over the current server server.Comments = c.commentQueue.DequeueAllComments() c.Servers = append(c.Servers, server) } func (c *NgxConfig) parseUpstream(scanner *bufio.Scanner) { upstream := &NgxUpstream{} for scanner.Scan() { d := NgxDirective{} text := strings.TrimSpace(scanner.Text()) // escape empty line or comment line if len(text) < 1 || text[0] == '#' { return } sep := len(text) - 1 for k, v := range text { if unicode.IsSpace(v) { sep = k break } } d.Directive = text[0:sep] d.Params = strings.Trim(text[sep:], ";") if d.Directive == Server { upstream.Directives = append(upstream.Directives, &d) } else if upstream.Name == "" { upstream.Name = d.Directive } } // attach comments which are over the current upstream upstream.Comments = c.commentQueue.DequeueAllComments() c.Upstreams = append(c.Upstreams, upstream) } func (s *NgxServer) parseDirective(d NgxDirective) { orig := d.Orig() // handle inline comments str, comments, _ := strings.Cut(orig, "#") if d.Directive == If { d.Params = "if " + d.Params d.Params = fmtCode(d.Params) s.Directives = append(s.Directives, &d) return } regExp := regexp.MustCompile("(\\S+?)\\s+?{?(.+)[;|}]") matchSlice := regExp.FindAllStringSubmatch(str, -1) for k, v := range matchSlice { // [[gzip_min_length 256; gzip_min_length 256] [gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; gzip_proxied expired no-cache no-store private no_last_modified no_etag auth] [gzip on; gzip on] [gzip_vary on; gzip_vary on] [location /x/ {} location /x/ {] [gzip_comp_level 4; gzip_comp_level 4]] if len(v) > 0 { scanner := bufio.NewScanner(strings.NewReader(v[0])) if scanner.Scan() { d = parseDirective(scanner) // inline location if d.Directive == Location { s.parseLocation(d.Orig()) } else { if k == 0 { d.Comments = s.commentQueue.DequeueAllComments() } else if k == len(matchSlice)-1 { d.Comments = comments } // trim right ';' d.TrimParams() // map[directive]=>[]Params s.Directives = append(s.Directives, &d) } } } } } func (s *NgxServer) parseLocation(str string) { path, content, _ := strings.Cut(str, "{") path = strings.TrimSpace(path) content = strings.TrimSpace(content) content = strings.Trim(content, "}") content = fmtCode(content) location := &NgxLocation{ Path: path, Content: content, } location.Comments = s.commentQueue.DequeueAllComments() s.Locations = append(s.Locations, location) }