github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/util/filters.go (about) 1 package util 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "path/filepath" 8 "strings" 9 "time" 10 11 "github.com/hanks177/podman/v4/pkg/timetype" 12 "github.com/pkg/errors" 13 ) 14 15 // ComputeUntilTimestamp extracts until timestamp from filters 16 func ComputeUntilTimestamp(filterValues []string) (time.Time, error) { 17 invalid := time.Time{} 18 if len(filterValues) != 1 { 19 return invalid, errors.Errorf("specify exactly one timestamp for until") 20 } 21 ts, err := timetype.GetTimestamp(filterValues[0], time.Now()) 22 if err != nil { 23 return invalid, err 24 } 25 seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0) 26 if err != nil { 27 return invalid, err 28 } 29 return time.Unix(seconds, nanoseconds), nil 30 } 31 32 // filtersFromRequests extracts the "filters" parameter from the specified 33 // http.Request. The parameter can either be a `map[string][]string` as done 34 // in new versions of Docker and libpod, or a `map[string]map[string]bool` as 35 // done in older versions of Docker. We have to do a bit of Yoga to support 36 // both - just as Docker does as well. 37 // 38 // Please refer to https://github.com/containers/podman/issues/6899 for some 39 // background. 40 func FiltersFromRequest(r *http.Request) ([]string, error) { 41 var ( 42 compatFilters map[string]map[string]bool 43 filters map[string][]string 44 libpodFilters []string 45 raw []byte 46 ) 47 48 if _, found := r.URL.Query()["filters"]; found { 49 raw = []byte(r.Form.Get("filters")) 50 } else if _, found := r.URL.Query()["Filters"]; found { 51 raw = []byte(r.Form.Get("Filters")) 52 } else { 53 return []string{}, nil 54 } 55 56 // Backwards compat with older versions of Docker. 57 if err := json.Unmarshal(raw, &compatFilters); err == nil { 58 for filterKey, filterMap := range compatFilters { 59 for filterValue, toAdd := range filterMap { 60 if toAdd { 61 libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", filterKey, filterValue)) 62 } 63 } 64 } 65 return libpodFilters, nil 66 } 67 68 if err := json.Unmarshal(raw, &filters); err != nil { 69 return nil, err 70 } 71 72 for filterKey, filterSlice := range filters { 73 for _, filterValue := range filterSlice { 74 libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", filterKey, filterValue)) 75 } 76 } 77 78 return libpodFilters, nil 79 } 80 81 // PrepareFilters prepares a *map[string][]string of filters to be later searched 82 // in lipod and compat API to get desired filters 83 func PrepareFilters(r *http.Request) (*map[string][]string, error) { 84 filtersList, err := FiltersFromRequest(r) 85 if err != nil { 86 return nil, err 87 } 88 filterMap := map[string][]string{} 89 for _, filter := range filtersList { 90 split := strings.SplitN(filter, "=", 2) 91 if len(split) > 1 { 92 filterMap[split[0]] = append(filterMap[split[0]], split[1]) 93 } 94 } 95 return &filterMap, nil 96 } 97 98 func matchPattern(pattern string, value string) bool { 99 if strings.Contains(pattern, "*") { 100 filter := fmt.Sprintf("*%s*", pattern) 101 filter = strings.ReplaceAll(filter, string(filepath.Separator), "|") 102 newName := strings.ReplaceAll(value, string(filepath.Separator), "|") 103 match, _ := filepath.Match(filter, newName) 104 return match 105 } 106 return false 107 } 108 109 // MatchLabelFilters matches labels and returns true if they are valid 110 func MatchLabelFilters(filterValues []string, labels map[string]string) bool { 111 outer: 112 for _, filterValue := range filterValues { 113 filterArray := strings.SplitN(filterValue, "=", 2) 114 filterKey := filterArray[0] 115 if len(filterArray) > 1 { 116 filterValue = filterArray[1] 117 } else { 118 filterValue = "" 119 } 120 for labelKey, labelValue := range labels { 121 if ((labelKey == filterKey) || matchPattern(filterKey, labelKey)) && (filterValue == "" || labelValue == filterValue) { 122 continue outer 123 } 124 } 125 return false 126 } 127 return true 128 }