Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(522)

Side by Side Diff: src/pkg/url/url.go

Issue 4893043: code review 4893043: url: new package (Closed)
Patch Set: Created 13 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2009 The Go Authors. All rights reserved. 1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 // Parse URLs (actually URIs, but that seems overly pedantic). 5 // Package URL parses and escapes URLs (actually URIs).
dsymonds 2011/08/15 09:20:23 to be more pedantic, although the objects that thi
6 // RFC 3986 6 // See RFC 3986.
7 7 package url
8 package http
9 8
10 import ( 9 import (
11 "os" 10 "os"
12 "strconv" 11 "strconv"
13 "strings" 12 "strings"
14 ) 13 )
15 14
16 // URLError reports an error and the operation and URL that caused it. 15 // Error reports an error and the operation and URL that caused it.
17 type URLError struct { 16 type Error struct {
18 Op string 17 Op string
19 URL string 18 URL string
20 Error os.Error 19 Error os.Error
21 } 20 }
22 21
23 func (e *URLError) String() string { return e.Op + " " + e.URL + ": " + e.Error. String() } 22 func (e *Error) String() string { return e.Op + " " + e.URL + ": " + e.Error.Str ing() }
24 23
25 func ishex(c byte) bool { 24 func ishex(c byte) bool {
26 switch { 25 switch {
27 case '0' <= c && c <= '9': 26 case '0' <= c && c <= '9':
28 return true 27 return true
29 case 'a' <= c && c <= 'f': 28 case 'a' <= c && c <= 'f':
30 return true 29 return true
31 case 'A' <= c && c <= 'F': 30 case 'A' <= c && c <= 'F':
32 return true 31 return true
33 } 32 }
(...skipping 15 matching lines...) Expand all
49 type encoding int 48 type encoding int
50 49
51 const ( 50 const (
52 encodePath encoding = 1 + iota 51 encodePath encoding = 1 + iota
53 encodeUserPassword 52 encodeUserPassword
54 encodeQueryComponent 53 encodeQueryComponent
55 encodeFragment 54 encodeFragment
56 encodeOpaque 55 encodeOpaque
57 ) 56 )
58 57
59 type URLEscapeError string 58 type EscapeError string
60 59
61 func (e URLEscapeError) String() string { 60 func (e EscapeError) String() string {
62 return "invalid URL escape " + strconv.Quote(string(e)) 61 return "invalid URL escape " + strconv.Quote(string(e))
63 } 62 }
64 63
65 // Return true if the specified character should be escaped when 64 // Return true if the specified character should be escaped when
66 // appearing in a URL string, according to RFC 2396. 65 // appearing in a URL string, according to RFC 2396.
67 // When 'all' is true the full range of reserved characters are matched. 66 // When 'all' is true the full range of reserved characters are matched.
68 func shouldEscape(c byte, mode encoding) bool { 67 func shouldEscape(c byte, mode encoding) bool {
69 // RFC 2396 §2.3 Unreserved characters (alphanum) 68 // RFC 2396 §2.3 Unreserved characters (alphanum)
70 if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' { 69 if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
71 return false 70 return false
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 // except that the leading / must be escaped. 105 // except that the leading / must be escaped.
107 // (We implement that case in String.) 106 // (We implement that case in String.)
108 return false 107 return false
109 } 108 }
110 } 109 }
111 110
112 // Everything else must be escaped. 111 // Everything else must be escaped.
113 return true 112 return true
114 } 113 }
115 114
116 // URLUnescape unescapes a string in ``URL encoded'' form, 115 // Unescape unescapes a string in ``URL encoded'' form,
117 // converting %AB into the byte 0xAB and '+' into ' ' (space). 116 // converting %AB into the byte 0xAB and '+' into ' ' (space).
118 // It returns an error if any % is not followed 117 // It returns an error if any % is not followed
119 // by two hexadecimal digits. 118 // by two hexadecimal digits.
120 // Despite the name, this encoding applies only to individual 119 // Despite the name, this encoding applies only to individual
121 // components of the query portion of the URL. 120 // components of the query portion of the URL.
122 func URLUnescape(s string) (string, os.Error) { 121 func Unescape(s string) (string, os.Error) {
123 » return urlUnescape(s, encodeQueryComponent) 122 » return unescape(s, encodeQueryComponent)
124 } 123 }
125 124
126 // urlUnescape is like URLUnescape but mode specifies 125 // unescape is like Unescape but mode specifies
127 // which section of the URL is being unescaped. 126 // which section of the URL is being unescaped.
128 func urlUnescape(s string, mode encoding) (string, os.Error) { 127 func unescape(s string, mode encoding) (string, os.Error) {
129 // Count %, check that they're well-formed. 128 // Count %, check that they're well-formed.
130 n := 0 129 n := 0
131 hasPlus := false 130 hasPlus := false
132 for i := 0; i < len(s); { 131 for i := 0; i < len(s); {
133 switch s[i] { 132 switch s[i] {
134 case '%': 133 case '%':
135 n++ 134 n++
136 if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { 135 if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
137 s = s[i:] 136 s = s[i:]
138 if len(s) > 3 { 137 if len(s) > 3 {
139 s = s[0:3] 138 s = s[0:3]
140 } 139 }
141 » » » » return "", URLEscapeError(s) 140 » » » » return "", EscapeError(s)
142 } 141 }
143 i += 3 142 i += 3
144 case '+': 143 case '+':
145 hasPlus = mode == encodeQueryComponent 144 hasPlus = mode == encodeQueryComponent
146 i++ 145 i++
147 default: 146 default:
148 i++ 147 i++
149 } 148 }
150 } 149 }
151 150
(...skipping 19 matching lines...) Expand all
171 i++ 170 i++
172 default: 171 default:
173 t[j] = s[i] 172 t[j] = s[i]
174 j++ 173 j++
175 i++ 174 i++
176 } 175 }
177 } 176 }
178 return string(t), nil 177 return string(t), nil
179 } 178 }
180 179
181 // URLEscape converts a string into ``URL encoded'' form. 180 // Escape converts a string into ``URL encoded'' form.
182 // Despite the name, this encoding applies only to individual 181 // Despite the name, this encoding applies only to individual
183 // components of the query portion of the URL. 182 // components of the query portion of the URL.
184 func URLEscape(s string) string { 183 func Escape(s string) string {
185 » return urlEscape(s, encodeQueryComponent) 184 » return escape(s, encodeQueryComponent)
186 } 185 }
187 186
188 func urlEscape(s string, mode encoding) string { 187 // EncodedPath returns the URL's path in "URL path encoded" form.
dsymonds 2011/08/15 09:20:23 this method seems odd all the way up here. move it
188 func (u *URL) EncodedPath() string {
189 » return escape(u.Path, encodePath)
190 }
191
192 func escape(s string, mode encoding) string {
189 spaceCount, hexCount := 0, 0 193 spaceCount, hexCount := 0, 0
190 for i := 0; i < len(s); i++ { 194 for i := 0; i < len(s); i++ {
191 c := s[i] 195 c := s[i]
192 if shouldEscape(c, mode) { 196 if shouldEscape(c, mode) {
193 if c == ' ' && mode == encodeQueryComponent { 197 if c == ' ' && mode == encodeQueryComponent {
194 spaceCount++ 198 spaceCount++
195 } else { 199 } else {
196 hexCount++ 200 hexCount++
197 } 201 }
198 } 202 }
(...skipping 27 matching lines...) Expand all
226 // as the form user or user:password and unescapes and returns 230 // as the form user or user:password and unescapes and returns
227 // the two halves. 231 // the two halves.
228 // 232 //
229 // This functionality should only be used with legacy web sites. 233 // This functionality should only be used with legacy web sites.
230 // RFC 2396 warns that interpreting Userinfo this way 234 // RFC 2396 warns that interpreting Userinfo this way
231 // ``is NOT RECOMMENDED, because the passing of authentication 235 // ``is NOT RECOMMENDED, because the passing of authentication
232 // information in clear text (such as URI) has proven to be a 236 // information in clear text (such as URI) has proven to be a
233 // security risk in almost every case where it has been used.'' 237 // security risk in almost every case where it has been used.''
234 func UnescapeUserinfo(rawUserinfo string) (user, password string, err os.Error) { 238 func UnescapeUserinfo(rawUserinfo string) (user, password string, err os.Error) {
235 u, p := split(rawUserinfo, ':', true) 239 u, p := split(rawUserinfo, ':', true)
236 » if user, err = urlUnescape(u, encodeUserPassword); err != nil { 240 » if user, err = unescape(u, encodeUserPassword); err != nil {
237 return "", "", err 241 return "", "", err
238 } 242 }
239 » if password, err = urlUnescape(p, encodeUserPassword); err != nil { 243 » if password, err = unescape(p, encodeUserPassword); err != nil {
240 return "", "", err 244 return "", "", err
241 } 245 }
242 return 246 return
243 } 247 }
244 248
245 // EscapeUserinfo combines user and password in the form 249 // EscapeUserinfo combines user and password in the form
246 // user:password (or just user if password is empty) and then 250 // user:password (or just user if password is empty) and then
247 // escapes it for use as the URL.RawUserinfo field. 251 // escapes it for use as the URL.RawUserinfo field.
248 // 252 //
249 // This functionality should only be used with legacy web sites. 253 // This functionality should only be used with legacy web sites.
250 // RFC 2396 warns that interpreting Userinfo this way 254 // RFC 2396 warns that interpreting Userinfo this way
251 // ``is NOT RECOMMENDED, because the passing of authentication 255 // ``is NOT RECOMMENDED, because the passing of authentication
252 // information in clear text (such as URI) has proven to be a 256 // information in clear text (such as URI) has proven to be a
253 // security risk in almost every case where it has been used.'' 257 // security risk in almost every case where it has been used.''
254 func EscapeUserinfo(user, password string) string { 258 func EscapeUserinfo(user, password string) string {
255 » raw := urlEscape(user, encodeUserPassword) 259 » raw := escape(user, encodeUserPassword)
256 if password != "" { 260 if password != "" {
257 » » raw += ":" + urlEscape(password, encodeUserPassword) 261 » » raw += ":" + escape(password, encodeUserPassword)
258 } 262 }
259 return raw 263 return raw
260 } 264 }
261 265
262 // A URL represents a parsed URL (technically, a URI reference). 266 // A URL represents a parsed URL (technically, a URI reference).
263 // The general form represented is: 267 // The general form represented is:
264 // scheme://[userinfo@]host/path[?query][#fragment] 268 // scheme://[userinfo@]host/path[?query][#fragment]
265 // The Raw, RawAuthority, RawPath, and RawQuery fields are in "wire format" 269 // The Raw, RawAuthority, RawPath, and RawQuery fields are in "wire format"
266 // (special characters must be hex-escaped if not meant to have special meaning) . 270 // (special characters must be hex-escaped if not meant to have special meaning) .
267 // All other fields are logical values; '+' or '%' represent themselves. 271 // All other fields are logical values; '+' or '%' represent themselves.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
317 if s[i] == c { 321 if s[i] == c {
318 if cutc { 322 if cutc {
319 return s[0:i], s[i+1:] 323 return s[0:i], s[i+1:]
320 } 324 }
321 return s[0:i], s[i:] 325 return s[0:i], s[i:]
322 } 326 }
323 } 327 }
324 return s, "" 328 return s, ""
325 } 329 }
326 330
327 // ParseURL parses rawurl into a URL structure. 331 // ParseURL parses rawurl into a URL structure.
dsymonds 2011/08/15 09:20:23 update name
328 // The string rawurl is assumed not to have a #fragment suffix. 332 // The string rawurl is assumed not to have a #fragment suffix.
329 // (Web browsers strip #fragment before sending the URL to a web server.) 333 // (Web browsers strip #fragment before sending the URL to a web server.)
330 // The rawurl may be relative or absolute. 334 // The rawurl may be relative or absolute.
331 func ParseURL(rawurl string) (url *URL, err os.Error) { 335 func Parse(rawurl string) (url *URL, err os.Error) {
332 » return parseURL(rawurl, false) 336 » return parse(rawurl, false)
333 } 337 }
334 338
335 // ParseRequestURL parses rawurl into a URL structure. It assumes that 339 // ParseRequest parses rawurl into a URL structure. It assumes that
336 // rawurl was received from an HTTP request, so the rawurl is interpreted 340 // rawurl was received from an HTTP request, so the rawurl is interpreted
337 // only as an absolute URI or an absolute path. 341 // only as an absolute URI or an absolute path.
338 // The string rawurl is assumed not to have a #fragment suffix. 342 // The string rawurl is assumed not to have a #fragment suffix.
339 // (Web browsers strip #fragment before sending the URL to a web server.) 343 // (Web browsers strip #fragment before sending the URL to a web server.)
340 func ParseRequestURL(rawurl string) (url *URL, err os.Error) { 344 func ParseRequest(rawurl string) (url *URL, err os.Error) {
341 » return parseURL(rawurl, true) 345 » return parse(rawurl, true)
342 } 346 }
343 347
344 // parseURL parses a URL from a string in one of two contexts. If 348 // parse parses a URL from a string in one of two contexts. If
345 // viaRequest is true, the URL is assumed to have arrived via an HTTP request, 349 // viaRequest is true, the URL is assumed to have arrived via an HTTP request,
346 // in which case only absolute URLs or path-absolute relative URLs are allowed. 350 // in which case only absolute URLs or path-absolute relative URLs are allowed.
347 // If viaRequest is false, all forms of relative URLs are allowed. 351 // If viaRequest is false, all forms of relative URLs are allowed.
348 func parseURL(rawurl string, viaRequest bool) (url *URL, err os.Error) { 352 func parse(rawurl string, viaRequest bool) (url *URL, err os.Error) {
349 var ( 353 var (
350 leadingSlash bool 354 leadingSlash bool
351 path string 355 path string
352 ) 356 )
353 357
354 if rawurl == "" { 358 if rawurl == "" {
355 err = os.NewError("empty url") 359 err = os.NewError("empty url")
356 goto Error 360 goto Error
357 } 361 }
358 url = new(URL) 362 url = new(URL)
359 url.Raw = rawurl 363 url.Raw = rawurl
360 364
361 // Split off possible leading "http:", "mailto:", etc. 365 // Split off possible leading "http:", "mailto:", etc.
362 // Cannot contain escaped characters. 366 // Cannot contain escaped characters.
363 if url.Scheme, path, err = getscheme(rawurl); err != nil { 367 if url.Scheme, path, err = getscheme(rawurl); err != nil {
364 goto Error 368 goto Error
365 } 369 }
366 leadingSlash = strings.HasPrefix(path, "/") 370 leadingSlash = strings.HasPrefix(path, "/")
367 371
368 if url.Scheme != "" && !leadingSlash { 372 if url.Scheme != "" && !leadingSlash {
369 // RFC 2396: 373 // RFC 2396:
370 // Absolute URI (has scheme) with non-rooted path 374 // Absolute URI (has scheme) with non-rooted path
371 // is uninterpreted. It doesn't even have a ?query. 375 // is uninterpreted. It doesn't even have a ?query.
372 // This is the case that handles mailto:name@example.com. 376 // This is the case that handles mailto:name@example.com.
373 url.RawPath = path 377 url.RawPath = path
374 378
375 » » if url.Path, err = urlUnescape(path, encodeOpaque); err != nil { 379 » » if url.Path, err = unescape(path, encodeOpaque); err != nil {
376 goto Error 380 goto Error
377 } 381 }
378 url.OpaquePath = true 382 url.OpaquePath = true
379 } else { 383 } else {
380 if viaRequest && !leadingSlash { 384 if viaRequest && !leadingSlash {
381 err = os.NewError("invalid URI for request") 385 err = os.NewError("invalid URI for request")
382 goto Error 386 goto Error
383 } 387 }
384 388
385 // Split off query before parsing path further. 389 // Split off query before parsing path further.
(...skipping 24 matching lines...) Expand all
410 // instead. Clients that wish to use RawAuthority will have to 414 // instead. Clients that wish to use RawAuthority will have to
411 // interpret it themselves: RFC 2396 does not define the meaning . 415 // interpret it themselves: RFC 2396 does not define the meaning .
412 416
413 if strings.Contains(rawHost, "%") { 417 if strings.Contains(rawHost, "%") {
414 // Host cannot contain escaped characters. 418 // Host cannot contain escaped characters.
415 err = os.NewError("hexadecimal escape in host") 419 err = os.NewError("hexadecimal escape in host")
416 goto Error 420 goto Error
417 } 421 }
418 url.Host = rawHost 422 url.Host = rawHost
419 423
420 » » if url.Path, err = urlUnescape(path, encodePath); err != nil { 424 » » if url.Path, err = unescape(path, encodePath); err != nil {
421 goto Error 425 goto Error
422 } 426 }
423 } 427 }
424 return url, nil 428 return url, nil
425 429
426 Error: 430 Error:
427 » return nil, &URLError{"parse", rawurl, err} 431 » return nil, &Error{"parse", rawurl, err}
428 432
429 } 433 }
430 434
431 // ParseURLReference is like ParseURL but allows a trailing #fragment. 435 // ParseWithReference is like Parse but allows a trailing #fragment.
432 func ParseURLReference(rawurlref string) (url *URL, err os.Error) { 436 func ParseWithReference(rawurlref string) (url *URL, err os.Error) {
433 // Cut off #frag. 437 // Cut off #frag.
434 rawurl, frag := split(rawurlref, '#', false) 438 rawurl, frag := split(rawurlref, '#', false)
435 » if url, err = ParseURL(rawurl); err != nil { 439 » if url, err = Parse(rawurl); err != nil {
436 return nil, err 440 return nil, err
437 } 441 }
438 url.Raw += frag 442 url.Raw += frag
439 url.RawPath += frag 443 url.RawPath += frag
440 if len(frag) > 1 { 444 if len(frag) > 1 {
441 frag = frag[1:] 445 frag = frag[1:]
442 » » if url.Fragment, err = urlUnescape(frag, encodeFragment); err != nil { 446 » » if url.Fragment, err = unescape(frag, encodeFragment); err != ni l {
443 » » » return nil, &URLError{"parse", rawurl, err} 447 » » » return nil, &Error{"parse", rawurl, err}
444 } 448 }
445 } 449 }
446 return url, nil 450 return url, nil
447 } 451 }
448 452
449 // String reassembles url into a valid URL string. 453 // String reassembles url into a valid URL string.
450 // 454 //
451 // There are redundant fields stored in the URL structure: 455 // There are redundant fields stored in the URL structure:
452 // the String method consults Scheme, Path, Host, RawUserinfo, 456 // the String method consults Scheme, Path, Host, RawUserinfo,
453 // RawQuery, and Fragment, but not Raw, RawPath or RawAuthority. 457 // RawQuery, and Fragment, but not Raw, RawPath or RawAuthority.
(...skipping 13 matching lines...) Expand all
467 result += info + "@" 471 result += info + "@"
468 } 472 }
469 result += url.Host 473 result += url.Host
470 } 474 }
471 if url.OpaquePath { 475 if url.OpaquePath {
472 path := url.Path 476 path := url.Path
473 if strings.HasPrefix(path, "/") { 477 if strings.HasPrefix(path, "/") {
474 result += "%2f" 478 result += "%2f"
475 path = path[1:] 479 path = path[1:]
476 } 480 }
477 » » result += urlEscape(path, encodeOpaque) 481 » » result += escape(path, encodeOpaque)
478 } else { 482 } else {
479 » » result += urlEscape(url.Path, encodePath) 483 » » result += escape(url.Path, encodePath)
480 } 484 }
481 if url.RawQuery != "" { 485 if url.RawQuery != "" {
482 result += "?" + url.RawQuery 486 result += "?" + url.RawQuery
483 } 487 }
484 if url.Fragment != "" { 488 if url.Fragment != "" {
485 » » result += "#" + urlEscape(url.Fragment, encodeFragment) 489 » » result += "#" + escape(url.Fragment, encodeFragment)
486 } 490 }
487 return result 491 return result
488 } 492 }
489 493
494 // Values maps a string key to a list of values.
495 // It is typically used for query parameters and form values.
496 // Unlike in the Header map, the keys in a Values map
dsymonds 2011/08/15 09:20:23 s/Header/http.Header/
497 // are case-sensitive.
498 type Values map[string][]string
499
500 // Get gets the first value associated with the given key.
501 // If there are no values associated with the key, Get returns
502 // the empty string. To access multiple values, use the map
503 // directly.
504 func (v Values) Get(key string) string {
505 if v == nil {
506 return ""
507 }
508 vs, ok := v[key]
509 if !ok || len(vs) == 0 {
510 return ""
511 }
512 return vs[0]
513 }
514
515 // Set sets the key to value. It replaces any existing
516 // values.
517 func (v Values) Set(key, value string) {
518 v[key] = []string{value}
519 }
520
521 // Add adds the key to value. It appends to any existing
522 // values associated with key.
523 func (v Values) Add(key, value string) {
524 v[key] = append(v[key], value)
525 }
526
527 // Del deletes the values associated with key.
528 func (v Values) Del(key string) {
529 v[key] = nil, false
530 }
531
532 // ParseQuery parses the URL-encoded query string and returns
533 // a map listing the values specified for each key.
534 // ParseQuery always returns a non-nil map containing all the
535 // valid query parameters found; err describes the first decoding error
536 // encountered, if any.
537 func ParseQuery(query string) (m Values, err os.Error) {
538 m = make(Values)
539 err = parseQuery(m, query)
540 return
541 }
542
543 func parseQuery(m Values, query string) (err os.Error) {
544 for _, kv := range strings.Split(query, "&") {
545 if len(kv) == 0 {
546 continue
547 }
548 kvPair := strings.SplitN(kv, "=", 2)
549
550 var key, value string
551 var e os.Error
552 key, e = Unescape(kvPair[0])
553 if e == nil && len(kvPair) > 1 {
554 value, e = Unescape(kvPair[1])
555 }
556 if e != nil {
557 err = e
558 continue
559 }
560 m[key] = append(m[key], value)
561 }
562 return err
563 }
564
490 // Encode encodes the values into ``URL encoded'' form. 565 // Encode encodes the values into ``URL encoded'' form.
491 // e.g. "foo=bar&bar=baz" 566 // e.g. "foo=bar&bar=baz"
492 func (v Values) Encode() string { 567 func (v Values) Encode() string {
493 if v == nil { 568 if v == nil {
494 return "" 569 return ""
495 } 570 }
496 parts := make([]string, 0, len(v)) // will be large enough for most uses 571 parts := make([]string, 0, len(v)) // will be large enough for most uses
497 for k, vs := range v { 572 for k, vs := range v {
498 » » prefix := URLEscape(k) + "=" 573 » » prefix := Escape(k) + "="
499 for _, v := range vs { 574 for _, v := range vs {
500 » » » parts = append(parts, prefix+URLEscape(v)) 575 » » » parts = append(parts, prefix+Escape(v))
501 } 576 }
502 } 577 }
503 return strings.Join(parts, "&") 578 return strings.Join(parts, "&")
504 } 579 }
505 580
506 // resolvePath applies special path segments from refs and applies 581 // resolvePath applies special path segments from refs and applies
507 // them to base, per RFC 2396. 582 // them to base, per RFC 2396.
508 func resolvePath(basepath string, refpath string) string { 583 func resolvePath(basepath string, refpath string) string {
509 base := strings.Split(basepath, "/") 584 base := strings.Split(basepath, "/")
510 refs := strings.Split(refpath, "/") 585 refs := strings.Split(refpath, "/")
(...skipping 20 matching lines...) Expand all
531 } 606 }
532 } 607 }
533 return strings.Join(base, "/") 608 return strings.Join(base, "/")
534 } 609 }
535 610
536 // IsAbs returns true if the URL is absolute. 611 // IsAbs returns true if the URL is absolute.
537 func (url *URL) IsAbs() bool { 612 func (url *URL) IsAbs() bool {
538 return url.Scheme != "" 613 return url.Scheme != ""
539 } 614 }
540 615
541 // ParseURL parses a URL in the context of a base URL. The URL in ref 616 // ParseURL parses a URL in the context of a base URL. The URL in ref
dsymonds 2011/08/15 09:20:23 update name
542 // may be relative or absolute. ParseURL returns nil, err on parse 617 // may be relative or absolute. ParseURL returns nil, err on parse
543 // failure, otherwise its return value is the same as ResolveReference. 618 // failure, otherwise its return value is the same as ResolveReference.
544 func (base *URL) ParseURL(ref string) (*URL, os.Error) { 619 func (base *URL) Parse(ref string) (*URL, os.Error) {
545 » refurl, err := ParseURL(ref) 620 » refurl, err := Parse(ref)
546 if err != nil { 621 if err != nil {
547 return nil, err 622 return nil, err
548 } 623 }
549 return base.ResolveReference(refurl), nil 624 return base.ResolveReference(refurl), nil
550 } 625 }
551 626
552 // ResolveReference resolves a URI reference to an absolute URI from 627 // ResolveReference resolves a URI reference to an absolute URI from
553 // an absolute base URI, per RFC 2396 Section 5.2. The URI reference 628 // an absolute base URI, per RFC 2396 Section 5.2. The URI reference
554 // may be relative or absolute. ResolveReference always returns a new 629 // may be relative or absolute. ResolveReference always returns a new
555 // URL instance, even if the returned URL is identical to either the 630 // URL instance, even if the returned URL is identical to either the
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 } 672 }
598 url.Raw = url.String() 673 url.Raw = url.String()
599 return url 674 return url
600 } 675 }
601 676
602 // Query parses RawQuery and returns the corresponding values. 677 // Query parses RawQuery and returns the corresponding values.
603 func (u *URL) Query() Values { 678 func (u *URL) Query() Values {
604 v, _ := ParseQuery(u.RawQuery) 679 v, _ := ParseQuery(u.RawQuery)
605 return v 680 return v
606 } 681 }
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b