LEFT | RIGHT |
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 // Package url parses URLs and implements query escaping. | 5 // Package url parses URLs and implements query escaping. |
6 // See RFC 3986. | 6 // See RFC 3986. |
7 package url | 7 package url |
8 | 8 |
9 import ( | 9 import ( |
10 "bytes" | 10 "bytes" |
11 "encoding/binary" | |
12 "errors" | 11 "errors" |
| 12 "fmt" |
13 "sort" | 13 "sort" |
14 "strconv" | 14 "strconv" |
15 "strings" | 15 "strings" |
16 ) | 16 ) |
17 | 17 |
18 // Error reports an error and the operation and URL that caused it. | 18 // Error reports an error and the operation and URL that caused it. |
19 type Error struct { | 19 type Error struct { |
20 Op string | 20 Op string |
21 URL string | 21 URL string |
22 Err error | 22 Err error |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 // and password. | 248 // and password. |
249 // This functionality should only be used with legacy web sites. | 249 // This functionality should only be used with legacy web sites. |
250 // RFC 2396 warns that interpreting Userinfo this way | 250 // RFC 2396 warns that interpreting Userinfo this way |
251 // ``is NOT RECOMMENDED, because the passing of authentication | 251 // ``is NOT RECOMMENDED, because the passing of authentication |
252 // information in clear text (such as URI) has proven to be a | 252 // information in clear text (such as URI) has proven to be a |
253 // security risk in almost every case where it has been used.'' | 253 // security risk in almost every case where it has been used.'' |
254 func UserPassword(username, password string) *Userinfo { | 254 func UserPassword(username, password string) *Userinfo { |
255 return &Userinfo{username, password, true} | 255 return &Userinfo{username, password, true} |
256 } | 256 } |
257 | 257 |
| 258 // ParseUserinfo parses a string with username and password |
| 259 // separated by a ':' and returns a Userinfo. Note that |
| 260 // the characters ':' in the username and password |
| 261 // should be escaped, otherwise an error will be returned. |
| 262 func ParseUserinfo(val string) (*Userinfo, error) { |
| 263 parts := strings.Split(val, ":") |
| 264 if len(parts) > 2 { |
| 265 return nil, fmt.Errorf("invalid Userinfo: %q", val) |
| 266 } |
| 267 u, err := unescape(parts[0], encodeUserPassword) |
| 268 if err != nil { |
| 269 return nil, err |
| 270 } |
| 271 if len(parts) == 1 { |
| 272 return User(u), nil |
| 273 } |
| 274 p, err := unescape(parts[1], encodeUserPassword) |
| 275 if err != nil { |
| 276 return nil, err |
| 277 } |
| 278 return UserPassword(u, p), nil |
| 279 } |
| 280 |
258 // The Userinfo type is an immutable encapsulation of username and | 281 // The Userinfo type is an immutable encapsulation of username and |
259 // password details for a URL. An existing Userinfo value is guaranteed | 282 // password details for a URL. An existing Userinfo value is guaranteed |
260 // to have a username set (potentially empty, as allowed by RFC 2396), | 283 // to have a username set (potentially empty, as allowed by RFC 2396), |
261 // and optionally a password. | 284 // and optionally a password. |
262 type Userinfo struct { | 285 type Userinfo struct { |
263 username string | 286 username string |
264 password string | 287 password string |
265 passwordSet bool | 288 passwordSet bool |
266 } | 289 } |
267 | 290 |
(...skipping 11 matching lines...) Expand all Loading... |
279 } | 302 } |
280 | 303 |
281 // String returns the encoded userinfo information in the standard form | 304 // String returns the encoded userinfo information in the standard form |
282 // of "username[:password]". | 305 // of "username[:password]". |
283 func (u *Userinfo) String() string { | 306 func (u *Userinfo) String() string { |
284 s := escape(u.username, encodeUserPassword) | 307 s := escape(u.username, encodeUserPassword) |
285 if u.passwordSet { | 308 if u.passwordSet { |
286 s += ":" + escape(u.password, encodeUserPassword) | 309 s += ":" + escape(u.password, encodeUserPassword) |
287 } | 310 } |
288 return s | 311 return s |
289 } | |
290 | |
291 // Implement GobEncoder/GobDecoder so UserInfo and URL objects can be serialized | |
292 func (u *Userinfo) GobEncode() ([]byte, error) { | |
293 buf := bytes.NewBuffer(nil) | |
294 ul := int16(len(u.username)) | |
295 if err := binary.Write(buf, binary.BigEndian, ul); err != nil { | |
296 return nil, err | |
297 } | |
298 if _, err := buf.WriteString(u.username); err != nil { | |
299 return nil, err | |
300 } | |
301 if u.passwordSet { | |
302 pl := int16(len(u.password)) | |
303 if err := binary.Write(buf, binary.BigEndian, pl); err != nil { | |
304 return nil, err | |
305 } | |
306 if _, err := buf.WriteString(u.password); err != nil { | |
307 return nil, err | |
308 } | |
309 } else { | |
310 if err := binary.Write(buf, binary.BigEndian, int16(-1)); err !=
nil { | |
311 return nil, err | |
312 } | |
313 } | |
314 return buf.Bytes(), nil | |
315 } | |
316 | |
317 func (u *Userinfo) GobDecode(b []byte) error { | |
318 r := bytes.NewReader(b) | |
319 var ul int16 | |
320 if err := binary.Read(r, binary.BigEndian, &ul); err != nil { | |
321 return err | |
322 } | |
323 if ul > 0 { | |
324 ub := make([]byte, int(ul)) | |
325 if _, err := r.Read(ub); err != nil { | |
326 return err | |
327 } | |
328 u.username = string(ub) | |
329 } | |
330 var pl int16 | |
331 if err := binary.Read(r, binary.BigEndian, &pl); err != nil { | |
332 return err | |
333 } | |
334 if pl >= 0 { | |
335 u.passwordSet = true | |
336 if pl > 0 { | |
337 pb := make([]byte, int(pl)) | |
338 if _, err := r.Read(pb); err != nil { | |
339 return err | |
340 } | |
341 u.password = string(pb) | |
342 } | |
343 } | |
344 return nil | |
345 } | 312 } |
346 | 313 |
347 // Maybe rawurl is of the form scheme:path. | 314 // Maybe rawurl is of the form scheme:path. |
348 // (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*) | 315 // (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*) |
349 // If so, return scheme, path; else return "", rawurl. | 316 // If so, return scheme, path; else return "", rawurl. |
350 func getscheme(rawurl string) (scheme, path string, err error) { | 317 func getscheme(rawurl string) (scheme, path string, err error) { |
351 for i := 0; i < len(rawurl); i++ { | 318 for i := 0; i < len(rawurl); i++ { |
352 c := rawurl[i] | 319 c := rawurl[i] |
353 switch { | 320 switch { |
354 case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z': | 321 case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z': |
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
745 } else { | 712 } else { |
746 if strings.HasPrefix(result, "//") { | 713 if strings.HasPrefix(result, "//") { |
747 result = u.Scheme + ":" + result | 714 result = u.Scheme + ":" + result |
748 } | 715 } |
749 } | 716 } |
750 if u.RawQuery != "" { | 717 if u.RawQuery != "" { |
751 result += "?" + u.RawQuery | 718 result += "?" + u.RawQuery |
752 } | 719 } |
753 return result | 720 return result |
754 } | 721 } |
LEFT | RIGHT |