package utils import ( "errors" "fmt" "net/http" "strings" ) const restURLPatternHeaderKey = "Owncast-Resturl-Pattern" // takes the segment pattern of an Url string and returns the segment before the first dynamic REST parameter. func getPatternForRestEndpoint(pattern string) string { firstIndex := strings.Index(pattern, "/{") if firstIndex == -1 { return pattern } return strings.TrimRight(pattern[:firstIndex], "/") + "/" } func zip2D(iterable1 *[]string, iterable2 *[]string) map[string]string { dict := make(map[string]string) for index, key := range *iterable1 { dict[key] = (*iterable2)[index] } return dict } func mapPatternWithRequestURL(pattern string, requestURL string) (map[string]string, error) { patternSplit := strings.Split(pattern, "/") requestURLSplit := strings.Split(requestURL, "/") if len(patternSplit) == len(requestURLSplit) { return zip2D(&patternSplit, &requestURLSplit), nil } return nil, errors.New("the length of pattern and request Url does not match") } func readParameter(pattern string, requestURL string, paramName string) (string, error) { all, err := mapPatternWithRequestURL(pattern, requestURL) if err != nil { return "", err } if value, exists := all[fmt.Sprintf("{%s}", paramName)]; exists { return value, nil } return "", fmt.Errorf("parameter with name %s not found", paramName) } // ReadRestURLParameter will return the parameter from the request of the requested name. func ReadRestURLParameter(r *http.Request, parameterName string) (string, error) { pattern, found := r.Header[restURLPatternHeaderKey] if !found { return "", fmt.Errorf("this HandlerFunc is not marked as REST-Endpoint. Cannot read Parameter '%s' from Request", parameterName) } return readParameter(pattern[0], r.URL.Path, parameterName) } // RestEndpoint wraps a handler to use the rest endpoint helper. func RestEndpoint(pattern string, handler http.HandlerFunc) (string, http.HandlerFunc) { baseURL := getPatternForRestEndpoint(pattern) return baseURL, func(w http.ResponseWriter, r *http.Request) { r.Header[restURLPatternHeaderKey] = []string{pattern} handler(w, r) } }