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  }