github.com/mcuadros/ascode@v1.3.1/starlark/module/url/url.go (about) 1 package url 2 3 import ( 4 "net/url" 5 "sync" 6 7 "go.starlark.net/starlark" 8 "go.starlark.net/starlarkstruct" 9 ) 10 11 const ( 12 // ModuleName defines the expected name for this Module when used 13 // in starlark's load() function, eg: load('io/ioutil', 'json') 14 ModuleName = "url" 15 16 pathEscapeFuncName = "path_escape" 17 pathUnescapeFuncName = "path_unescape" 18 queryEscapeFuncName = "query_escape" 19 queryUnescapeFuncName = "query_unescape" 20 parseFuncName = "parse" 21 ) 22 23 var ( 24 once sync.Once 25 ioutilModule starlark.StringDict 26 ) 27 28 // LoadModule loads the url module. 29 // It is concurrency-safe and idempotent. 30 // 31 // outline: url 32 // url parses URLs and implements query escaping. 33 // path: url 34 func LoadModule() (starlark.StringDict, error) { 35 once.Do(func() { 36 ioutilModule = starlark.StringDict{ 37 "url": &starlarkstruct.Module{ 38 Name: "url", 39 Members: starlark.StringDict{ 40 pathEscapeFuncName: starlark.NewBuiltin(pathEscapeFuncName, PathEscape), 41 pathUnescapeFuncName: starlark.NewBuiltin(pathUnescapeFuncName, PathUnescape), 42 queryEscapeFuncName: starlark.NewBuiltin(queryEscapeFuncName, QueryEscape), 43 queryUnescapeFuncName: starlark.NewBuiltin(queryUnescapeFuncName, QueryUnescape), 44 parseFuncName: starlark.NewBuiltin(parseFuncName, Parse), 45 }, 46 }, 47 } 48 }) 49 50 return ioutilModule, nil 51 } 52 53 // PathEscape escapes the string so it can be safely placed inside a URL path 54 // segment, replacing special characters (including /) with %XX sequences as 55 // needed. 56 // 57 // outline: url 58 // functions: 59 // path_escape(s) 60 // escapes the string so it can be safely placed inside a URL path 61 // segment, replacing special characters (including /) with %XX 62 // sequences as needed. 63 // params: 64 // s string 65 func PathEscape(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 66 var s string 67 68 err := starlark.UnpackArgs(pathEscapeFuncName, args, kwargs, "s", &s) 69 if err != nil { 70 return nil, err 71 } 72 73 return starlark.String(url.PathEscape(s)), nil 74 } 75 76 // PathUnescape does the inverse transformation of PathEscape, converting each 77 // 3-byte encoded substring of the form "%AB" into the hex-decoded byte 0xAB. It 78 // returns an error if any % is not followed by two hexadecimal digits. 79 // PathUnescape is identical to QueryUnescape except that it does not unescape 80 // '+' to ' ' (space). 81 // 82 // outline: url 83 // functions: 84 // path_unescape(s) 85 // does the inverse transformation of path_escape, converting each 86 // 3-byte encoded substring of the form "%AB" into the hex-decoded byte 87 // 0xAB. It returns an error if any % is not followed by two hexadecimal 88 // digits. path_unescape is identical to query_unescape except that it 89 // does not unescape '+' to ' ' (space). 90 // params: 91 // s string 92 func PathUnescape(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 93 var s string 94 95 err := starlark.UnpackArgs(pathUnescapeFuncName, args, kwargs, "s", &s) 96 if err != nil { 97 return nil, err 98 } 99 100 output, err := url.PathUnescape(s) 101 return starlark.String(output), err 102 } 103 104 // QueryEscape escapes the string so it can be safely placed inside a URL query. 105 // 106 // outline: url 107 // functions: 108 // path_escape(s) 109 // escapes the string so it can be safely placed inside a URL query. 110 // params: 111 // s string 112 func QueryEscape(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 113 var s string 114 115 err := starlark.UnpackArgs(queryEscapeFuncName, args, kwargs, "s", &s) 116 if err != nil { 117 return nil, err 118 } 119 120 return starlark.String(url.QueryEscape(s)), nil 121 } 122 123 // QueryUnescape does the inverse transformation of QueryEscape, converting each 124 // 3-byte encoded substring of the form "%AB" into the hex-decoded byte 0xAB. 125 // It returns an error if any % is not followed by two hexadecimal digits. 126 // 127 // outline: url 128 // functions: 129 // path_unescape(s) 130 // does the inverse transformation of query_escape, converting each 131 // 3-byte encoded substring of the form "%AB" into the hex-decoded byte 132 // 0xAB. It returns an error if any % is not followed by two hexadecimal 133 // digits. 134 // params: 135 // s string 136 func QueryUnescape(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 137 var s string 138 139 err := starlark.UnpackArgs(queryUnescapeFuncName, args, kwargs, "s", &s) 140 if err != nil { 141 return nil, err 142 } 143 144 output, err := url.QueryUnescape(s) 145 return starlark.String(output), err 146 } 147 148 type sString = starlark.String 149 150 // URL represents a parsed URL (technically, a URI reference). 151 // 152 // outline: url 153 // types: 154 // URL 155 // Represents a parsed URL (technically, a URI reference). 156 // 157 // fields: 158 // scheme string 159 // opaque string 160 // Encoded opaque data. 161 // username string 162 // Username information. 163 // password string 164 // Password information. 165 // host string 166 // Host or host:port. 167 // path string 168 // Path (relative paths may omit leading slash). 169 // raw_query string 170 // Encoded query values, without '?'. 171 // fragment string 172 // Fragment for references, without '#'. 173 // 174 type URL struct { 175 url url.URL 176 sString 177 } 178 179 // Parse parses rawurl into a URL structure. 180 // 181 // outline: url 182 // functions: 183 // parse(rawurl) URL 184 // Parse parses rawurl into a URL structure. 185 // 186 // params: 187 // rawurl string 188 // rawurl may be relative (a path, without a host) or absolute 189 // (starting with a scheme). Trying to parse a hostname and path 190 // without a scheme is invalid but may not necessarily return an 191 // error, due to parsing ambiguities. 192 func Parse( 193 thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple, 194 ) (starlark.Value, error) { 195 196 var rawurl string 197 err := starlark.UnpackArgs(parseFuncName, args, kwargs, "rawurl", &rawurl) 198 if err != nil { 199 return nil, err 200 } 201 202 url, err := url.Parse(rawurl) 203 if err != nil { 204 return starlark.None, err 205 } 206 207 return &URL{ 208 url: *url, 209 sString: starlark.String(url.String()), 210 }, nil 211 } 212 213 func (u *URL) Attr(name string) (starlark.Value, error) { 214 switch name { 215 case "scheme": 216 return starlark.String(u.url.Scheme), nil 217 case "opaque": 218 return starlark.String(u.url.Opaque), nil 219 case "username": 220 if u.url.User == nil { 221 return starlark.None, nil 222 } 223 224 return starlark.String(u.url.User.Username()), nil 225 case "password": 226 if u.url.User == nil { 227 return starlark.None, nil 228 } 229 230 password, provided := u.url.User.Password() 231 if !provided { 232 return starlark.None, nil 233 } 234 235 return starlark.String(password), nil 236 case "host": 237 return starlark.String(u.url.Host), nil 238 case "path": 239 return starlark.String(u.url.Path), nil 240 case "raw_query": 241 return starlark.String(u.url.RawQuery), nil 242 case "fragment": 243 return starlark.String(u.url.Fragment), nil 244 } 245 246 return nil, nil 247 } 248 249 func (*URL) AttrNames() []string { 250 return []string{ 251 "scheme", "opaque", "username", "password", "host", "path", 252 "raw_query", "fragment", 253 } 254 }