go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/luciexe/host/buildmerge/util.go (about) 1 // Copyright 2021 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package buildmerge 16 17 import ( 18 "strings" 19 20 "go.chromium.org/luci/common/errors" 21 "go.chromium.org/luci/logdog/common/types" 22 ) 23 24 // absolutizeURLs absolutizes the provided `logURL` and `viewURL`. 25 // 26 // No-op if both `logURL` and `viewURL` are absolute urls. Absolute url here 27 // means url that has valid scheme. A valid scheme must be 28 // `[a-zA-Z][a-zA-Z0-9+-.]*“ according to 29 // https://datatracker.ietf.org/doc/html/rfc3986#section-3.1 30 // 31 // If `logURL` is relative, calculate the return urls using `calcFn`. The 32 // provided `viewURL` will be omitted. 33 // 34 // Returns error if any of the following conditions are true: 35 // - `logURL` is an absolute url but `viewURL` is empty. 36 // - `logURL` is an absolute url but `viewURL` is not an absolute url. 37 // - `logURL` is a relative url but not a valid logdog stream. 38 // 39 // The input `logURL` and `viewURL` will be returned verbatim on errors. 40 func absolutizeURLs(logURL, viewURL string, ns types.StreamName, calcFn CalcURLFn) (retLogURL, retViewURL string, err error) { 41 retLogURL, retViewURL = logURL, viewURL 42 if isAbs(logURL) { 43 switch { 44 case viewURL == "": 45 return retLogURL, retViewURL, errors.Reason("absolute log url is provided %q but view url is empty", logURL).Err() 46 case !isAbs(viewURL): 47 return retLogURL, retViewURL, errors.Reason("expected absolute view url, got %q", viewURL).Err() 48 } 49 // both urls are absolute. 50 return retLogURL, retViewURL, nil 51 } 52 53 stream := types.StreamName(logURL) 54 if serr := stream.Validate(); serr != nil { 55 return retLogURL, retViewURL, errors.Annotate(serr, "bad log url %q", logURL).Err() 56 } 57 retLogURL, retViewURL = calcFn(ns, stream) 58 return retLogURL, retViewURL, nil 59 } 60 61 func isAbs(url string) bool { 62 idx := strings.Index(url, "://") 63 if idx <= 0 { 64 return false 65 } 66 scheme := url[:idx] 67 for i := 0; i < len(scheme); i++ { 68 c := scheme[i] 69 switch { 70 case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z': 71 // always valid 72 case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.': 73 if i != 0 { 74 return false 75 } 76 } 77 } 78 return true 79 }