uri.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. package fasthttp
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "path/filepath"
  8. "strconv"
  9. "sync"
  10. )
  11. // AcquireURI returns an empty URI instance from the pool.
  12. //
  13. // Release the URI with ReleaseURI after the URI is no longer needed.
  14. // This allows reducing GC load.
  15. func AcquireURI() *URI {
  16. return uriPool.Get().(*URI)
  17. }
  18. // ReleaseURI releases the URI acquired via AcquireURI.
  19. //
  20. // The released URI mustn't be used after releasing it, otherwise data races
  21. // may occur.
  22. func ReleaseURI(u *URI) {
  23. u.Reset()
  24. uriPool.Put(u)
  25. }
  26. var uriPool = &sync.Pool{
  27. New: func() any {
  28. return &URI{}
  29. },
  30. }
  31. // URI represents URI :) .
  32. //
  33. // It is forbidden copying URI instances. Create new instance and use CopyTo
  34. // instead.
  35. //
  36. // URI instance MUST NOT be used from concurrently running goroutines.
  37. type URI struct {
  38. noCopy noCopy
  39. queryArgs Args
  40. pathOriginal []byte
  41. scheme []byte
  42. path []byte
  43. queryString []byte
  44. hash []byte
  45. host []byte
  46. fullURI []byte
  47. requestURI []byte
  48. username []byte
  49. password []byte
  50. parsedQueryArgs bool
  51. // Path values are sent as-is without normalization.
  52. //
  53. // Disabled path normalization may be useful for proxying incoming requests
  54. // to servers that are expecting paths to be forwarded as-is.
  55. //
  56. // By default path values are normalized, i.e.
  57. // extra slashes are removed, special characters are encoded.
  58. DisablePathNormalizing bool
  59. }
  60. // CopyTo copies uri contents to dst.
  61. func (u *URI) CopyTo(dst *URI) {
  62. dst.Reset()
  63. dst.pathOriginal = append(dst.pathOriginal, u.pathOriginal...)
  64. dst.scheme = append(dst.scheme, u.scheme...)
  65. dst.path = append(dst.path, u.path...)
  66. dst.queryString = append(dst.queryString, u.queryString...)
  67. dst.hash = append(dst.hash, u.hash...)
  68. dst.host = append(dst.host, u.host...)
  69. dst.username = append(dst.username, u.username...)
  70. dst.password = append(dst.password, u.password...)
  71. u.queryArgs.CopyTo(&dst.queryArgs)
  72. dst.parsedQueryArgs = u.parsedQueryArgs
  73. dst.DisablePathNormalizing = u.DisablePathNormalizing
  74. // fullURI and requestURI shouldn't be copied, since they are created
  75. // from scratch on each FullURI() and RequestURI() call.
  76. }
  77. // Hash returns URI hash, i.e. qwe of http://aaa.com/foo/bar?baz=123#qwe .
  78. //
  79. // The returned bytes are valid until the next URI method call.
  80. func (u *URI) Hash() []byte {
  81. return u.hash
  82. }
  83. // SetHash sets URI hash.
  84. func (u *URI) SetHash(hash string) {
  85. u.hash = append(u.hash[:0], hash...)
  86. }
  87. // SetHashBytes sets URI hash.
  88. func (u *URI) SetHashBytes(hash []byte) {
  89. u.hash = append(u.hash[:0], hash...)
  90. }
  91. // Username returns URI username
  92. //
  93. // The returned bytes are valid until the next URI method call.
  94. func (u *URI) Username() []byte {
  95. return u.username
  96. }
  97. // SetUsername sets URI username.
  98. func (u *URI) SetUsername(username string) {
  99. u.username = append(u.username[:0], username...)
  100. }
  101. // SetUsernameBytes sets URI username.
  102. func (u *URI) SetUsernameBytes(username []byte) {
  103. u.username = append(u.username[:0], username...)
  104. }
  105. // Password returns URI password.
  106. //
  107. // The returned bytes are valid until the next URI method call.
  108. func (u *URI) Password() []byte {
  109. return u.password
  110. }
  111. // SetPassword sets URI password.
  112. func (u *URI) SetPassword(password string) {
  113. u.password = append(u.password[:0], password...)
  114. }
  115. // SetPasswordBytes sets URI password.
  116. func (u *URI) SetPasswordBytes(password []byte) {
  117. u.password = append(u.password[:0], password...)
  118. }
  119. // QueryString returns URI query string,
  120. // i.e. baz=123 of http://aaa.com/foo/bar?baz=123#qwe .
  121. //
  122. // The returned bytes are valid until the next URI method call.
  123. func (u *URI) QueryString() []byte {
  124. return u.queryString
  125. }
  126. // SetQueryString sets URI query string.
  127. func (u *URI) SetQueryString(queryString string) {
  128. u.queryString = append(u.queryString[:0], queryString...)
  129. u.parsedQueryArgs = false
  130. }
  131. // SetQueryStringBytes sets URI query string.
  132. func (u *URI) SetQueryStringBytes(queryString []byte) {
  133. u.queryString = append(u.queryString[:0], queryString...)
  134. u.parsedQueryArgs = false
  135. }
  136. // Path returns URI path, i.e. /foo/bar of http://aaa.com/foo/bar?baz=123#qwe .
  137. //
  138. // The returned path is always urldecoded and normalized,
  139. // i.e. '//f%20obar/baz/../zzz' becomes '/f obar/zzz'.
  140. //
  141. // The returned bytes are valid until the next URI method call.
  142. func (u *URI) Path() []byte {
  143. path := u.path
  144. if len(path) == 0 {
  145. path = strSlash
  146. }
  147. return path
  148. }
  149. // SetPath sets URI path.
  150. func (u *URI) SetPath(path string) {
  151. u.pathOriginal = append(u.pathOriginal[:0], path...)
  152. u.path = normalizePath(u.path, u.pathOriginal)
  153. }
  154. // SetPathBytes sets URI path.
  155. func (u *URI) SetPathBytes(path []byte) {
  156. u.pathOriginal = append(u.pathOriginal[:0], path...)
  157. u.path = normalizePath(u.path, u.pathOriginal)
  158. }
  159. // PathOriginal returns the original path from requestURI passed to URI.Parse().
  160. //
  161. // The returned bytes are valid until the next URI method call.
  162. func (u *URI) PathOriginal() []byte {
  163. return u.pathOriginal
  164. }
  165. // Scheme returns URI scheme, i.e. http of http://aaa.com/foo/bar?baz=123#qwe .
  166. //
  167. // Returned scheme is always lowercased.
  168. //
  169. // The returned bytes are valid until the next URI method call.
  170. func (u *URI) Scheme() []byte {
  171. scheme := u.scheme
  172. if len(scheme) == 0 {
  173. scheme = strHTTP
  174. }
  175. return scheme
  176. }
  177. // SetScheme sets URI scheme, i.e. http, https, ftp, etc.
  178. func (u *URI) SetScheme(scheme string) {
  179. u.scheme = append(u.scheme[:0], scheme...)
  180. lowercaseBytes(u.scheme)
  181. }
  182. // SetSchemeBytes sets URI scheme, i.e. http, https, ftp, etc.
  183. func (u *URI) SetSchemeBytes(scheme []byte) {
  184. u.scheme = append(u.scheme[:0], scheme...)
  185. lowercaseBytes(u.scheme)
  186. }
  187. func (u *URI) isHTTPS() bool {
  188. return bytes.Equal(u.scheme, strHTTPS)
  189. }
  190. func (u *URI) isHTTP() bool {
  191. return len(u.scheme) == 0 || bytes.Equal(u.scheme, strHTTP)
  192. }
  193. // Reset clears uri.
  194. func (u *URI) Reset() {
  195. u.pathOriginal = u.pathOriginal[:0]
  196. u.scheme = u.scheme[:0]
  197. u.path = u.path[:0]
  198. u.queryString = u.queryString[:0]
  199. u.hash = u.hash[:0]
  200. u.username = u.username[:0]
  201. u.password = u.password[:0]
  202. u.host = u.host[:0]
  203. u.queryArgs.Reset()
  204. u.parsedQueryArgs = false
  205. u.DisablePathNormalizing = false
  206. // There is no need in u.fullURI = u.fullURI[:0], since full uri
  207. // is calculated on each call to FullURI().
  208. // There is no need in u.requestURI = u.requestURI[:0], since requestURI
  209. // is calculated on each call to RequestURI().
  210. }
  211. // Host returns host part, i.e. aaa.com of http://aaa.com/foo/bar?baz=123#qwe .
  212. //
  213. // Host is always lowercased.
  214. //
  215. // The returned bytes are valid until the next URI method call.
  216. func (u *URI) Host() []byte {
  217. return u.host
  218. }
  219. // SetHost sets host for the uri.
  220. func (u *URI) SetHost(host string) {
  221. u.host = append(u.host[:0], host...)
  222. lowercaseBytes(u.host)
  223. }
  224. // SetHostBytes sets host for the uri.
  225. func (u *URI) SetHostBytes(host []byte) {
  226. u.host = append(u.host[:0], host...)
  227. lowercaseBytes(u.host)
  228. }
  229. var ErrorInvalidURI = errors.New("invalid uri")
  230. // Parse initializes URI from the given host and uri.
  231. //
  232. // host may be nil. In this case uri must contain fully qualified uri,
  233. // i.e. with scheme and host. http is assumed if scheme is omitted.
  234. //
  235. // uri may contain e.g. RequestURI without scheme and host if host is non-empty.
  236. func (u *URI) Parse(host, uri []byte) error {
  237. return u.parse(host, uri, false)
  238. }
  239. func (u *URI) parse(host, uri []byte, isTLS bool) error {
  240. u.Reset()
  241. if stringContainsCTLByte(uri) {
  242. return ErrorInvalidURI
  243. }
  244. if len(host) == 0 || bytes.Contains(uri, strColonSlashSlash) {
  245. scheme, newHost, newURI := splitHostURI(host, uri)
  246. if len(scheme) > 0 && !isValidScheme(scheme) {
  247. return fmt.Errorf("invalid scheme %q", scheme)
  248. }
  249. u.SetSchemeBytes(scheme)
  250. host = newHost
  251. uri = newURI
  252. }
  253. if isTLS {
  254. u.SetSchemeBytes(strHTTPS)
  255. }
  256. if n := bytes.LastIndexByte(host, '@'); n >= 0 {
  257. auth := host[:n]
  258. if !validUserinfo(auth) {
  259. return ErrorInvalidURI
  260. }
  261. host = host[n+1:]
  262. if n := bytes.IndexByte(auth, ':'); n >= 0 {
  263. u.username = append(u.username[:0], auth[:n]...)
  264. u.password = append(u.password[:0], auth[n+1:]...)
  265. } else {
  266. u.username = append(u.username[:0], auth...)
  267. u.password = u.password[:0]
  268. }
  269. }
  270. u.host = append(u.host, host...)
  271. parsedHost, err := parseHost(u.host)
  272. if err != nil {
  273. return err
  274. }
  275. u.host = parsedHost
  276. lowercaseBytes(u.host)
  277. b := uri
  278. queryIndex := bytes.IndexByte(b, '?')
  279. fragmentIndex := bytes.IndexByte(b, '#')
  280. // Ignore query in fragment part
  281. if fragmentIndex >= 0 && queryIndex > fragmentIndex {
  282. queryIndex = -1
  283. }
  284. if queryIndex < 0 && fragmentIndex < 0 {
  285. u.pathOriginal = append(u.pathOriginal, b...)
  286. u.path = normalizePath(u.path, u.pathOriginal)
  287. return nil
  288. }
  289. if queryIndex >= 0 {
  290. // Path is everything up to the start of the query
  291. u.pathOriginal = append(u.pathOriginal, b[:queryIndex]...)
  292. u.path = normalizePath(u.path, u.pathOriginal)
  293. if fragmentIndex < 0 {
  294. u.queryString = append(u.queryString, b[queryIndex+1:]...)
  295. } else {
  296. u.queryString = append(u.queryString, b[queryIndex+1:fragmentIndex]...)
  297. u.hash = append(u.hash, b[fragmentIndex+1:]...)
  298. }
  299. return nil
  300. }
  301. // fragmentIndex >= 0 && queryIndex < 0
  302. // Path is up to the start of fragment
  303. u.pathOriginal = append(u.pathOriginal, b[:fragmentIndex]...)
  304. u.path = normalizePath(u.path, u.pathOriginal)
  305. u.hash = append(u.hash, b[fragmentIndex+1:]...)
  306. return nil
  307. }
  308. func validUserinfo(userinfo []byte) bool {
  309. for _, c := range userinfo {
  310. switch {
  311. case 'A' <= c && c <= 'Z':
  312. continue
  313. case 'a' <= c && c <= 'z':
  314. continue
  315. case '0' <= c && c <= '9':
  316. continue
  317. }
  318. switch c {
  319. case '-', '.', '_', ':', '~', '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', '%', '@':
  320. continue
  321. default:
  322. return false
  323. }
  324. }
  325. return true
  326. }
  327. func isValidScheme(scheme []byte) bool {
  328. if len(scheme) == 0 {
  329. return false
  330. }
  331. first := scheme[0]
  332. if (first < 'a' || first > 'z') && (first < 'A' || first > 'Z') {
  333. return false
  334. }
  335. for i := 1; i < len(scheme); i++ {
  336. c := scheme[i]
  337. if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') {
  338. continue
  339. }
  340. switch c {
  341. case '+', '-', '.':
  342. continue
  343. }
  344. return false
  345. }
  346. return true
  347. }
  348. // parseHost parses host as an authority without user
  349. // information. That is, as host[:port].
  350. //
  351. // Based on https://github.com/golang/go/blob/8ac5cbe05d61df0a7a7c9a38ff33305d4dcfea32/src/net/url/url.go#L619
  352. //
  353. // The host is parsed and unescaped in place overwriting the contents of the host parameter.
  354. func parseHost(host []byte) ([]byte, error) {
  355. if len(host) > 0 && host[0] == '[' {
  356. // Parse an IP-Literal in RFC 3986 and RFC 6874.
  357. // E.g., "[fe80::1]", "[fe80::1%25en0]", "[fe80::1]:80".
  358. i := bytes.LastIndexByte(host, ']')
  359. if i < 0 {
  360. return nil, errors.New("missing ']' in host")
  361. }
  362. colonPort := host[i+1:]
  363. if !validOptionalPort(colonPort) {
  364. return nil, fmt.Errorf("invalid port %q after host", colonPort)
  365. }
  366. // RFC 6874 defines that %25 (%-encoded percent) introduces
  367. // the zone identifier, and the zone identifier can use basically
  368. // any %-encoding it likes. That's different from the host, which
  369. // can only %-encode non-ASCII bytes.
  370. // We do impose some restrictions on the zone, to avoid stupidity
  371. // like newlines.
  372. zone := bytes.Index(host[:i], []byte("%25"))
  373. if zone >= 0 {
  374. host1, err := unescape(host[:zone], encodeHost)
  375. if err != nil {
  376. return nil, err
  377. }
  378. host2, err := unescape(host[zone:i], encodeZone)
  379. if err != nil {
  380. return nil, err
  381. }
  382. host3, err := unescape(host[i:], encodeHost)
  383. if err != nil {
  384. return nil, err
  385. }
  386. return append(host1, append(host2, host3...)...), nil
  387. }
  388. } else {
  389. if bytes.ContainsAny(host, "[]") {
  390. return nil, fmt.Errorf("invalid host %q", host)
  391. }
  392. if i := bytes.LastIndexByte(host, ':'); i != -1 {
  393. if bytes.IndexByte(host[:i], ':') != -1 {
  394. return nil, fmt.Errorf("invalid host %q with multiple port delimiters", host)
  395. }
  396. colonPort := host[i:]
  397. if !validOptionalPort(colonPort) {
  398. return nil, fmt.Errorf("invalid port %q after host", colonPort)
  399. }
  400. }
  401. }
  402. var err error
  403. if host, err = unescape(host, encodeHost); err != nil {
  404. return nil, err
  405. }
  406. if err = validateIPv6Literal(host); err != nil {
  407. return nil, err
  408. }
  409. return host, nil
  410. }
  411. type encoding int
  412. const (
  413. encodeHost encoding = 1 + iota
  414. encodeZone
  415. )
  416. type EscapeError string
  417. func (e EscapeError) Error() string {
  418. return "invalid URL escape " + strconv.Quote(string(e))
  419. }
  420. type InvalidHostError string
  421. func (e InvalidHostError) Error() string {
  422. return "invalid character " + strconv.Quote(string(e)) + " in host name"
  423. }
  424. // unescape unescapes a string; the mode specifies
  425. // which section of the URL string is being unescaped.
  426. //
  427. // Based on https://github.com/golang/go/blob/8ac5cbe05d61df0a7a7c9a38ff33305d4dcfea32/src/net/url/url.go#L199
  428. //
  429. // Unescapes in place overwriting the contents of s and returning it.
  430. func unescape(s []byte, mode encoding) ([]byte, error) {
  431. // Count %, check that they're well-formed.
  432. n := 0
  433. for i := 0; i < len(s); {
  434. switch s[i] {
  435. case '%':
  436. n++
  437. if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
  438. s = s[i:]
  439. if len(s) > 3 {
  440. s = s[:3]
  441. }
  442. return nil, EscapeError(s)
  443. }
  444. // Per https://tools.ietf.org/html/rfc3986#page-21
  445. // in the host component %-encoding can only be used
  446. // for non-ASCII bytes.
  447. // But https://tools.ietf.org/html/rfc6874#section-2
  448. // introduces %25 being allowed to escape a percent sign
  449. // in IPv6 scoped-address literals. Yay.
  450. if mode == encodeHost && unhex(s[i+1]) < 8 && !bytes.Equal(s[i:i+3], []byte("%25")) {
  451. return nil, EscapeError(s[i : i+3])
  452. }
  453. if mode == encodeZone {
  454. // RFC 6874 says basically "anything goes" for zone identifiers
  455. // and that even non-ASCII can be redundantly escaped,
  456. // but it seems prudent to restrict %-escaped bytes here to those
  457. // that are valid host name bytes in their unescaped form.
  458. // That is, you can use escaping in the zone identifier but not
  459. // to introduce bytes you couldn't just write directly.
  460. // But Windows puts spaces here! Yay.
  461. v := unhex(s[i+1])<<4 | unhex(s[i+2])
  462. if !bytes.Equal(s[i:i+3], []byte("%25")) && v != ' ' && shouldEscape(v, encodeHost) {
  463. return nil, EscapeError(s[i : i+3])
  464. }
  465. }
  466. i += 3
  467. default:
  468. if (mode == encodeHost || mode == encodeZone) && s[i] < 0x80 && shouldEscape(s[i], mode) {
  469. return nil, InvalidHostError(s[i : i+1])
  470. }
  471. i++
  472. }
  473. }
  474. if n == 0 {
  475. return s, nil
  476. }
  477. t := s[:0]
  478. for i := 0; i < len(s); i++ {
  479. switch s[i] {
  480. case '%':
  481. t = append(t, unhex(s[i+1])<<4|unhex(s[i+2]))
  482. i += 2
  483. default:
  484. t = append(t, s[i])
  485. }
  486. }
  487. return t, nil
  488. }
  489. // Return true if the specified character should be escaped when
  490. // appearing in a URL string, according to RFC 3986.
  491. //
  492. // Please be informed that for now shouldEscape does not check all
  493. // reserved characters correctly. See https://github.com/golang/go/issues/5684.
  494. //
  495. // Based on https://github.com/golang/go/blob/8ac5cbe05d61df0a7a7c9a38ff33305d4dcfea32/src/net/url/url.go#L100
  496. func shouldEscape(c byte, mode encoding) bool {
  497. // §2.3 Unreserved characters (alphanum)
  498. if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
  499. return false
  500. }
  501. if mode == encodeHost || mode == encodeZone {
  502. // §3.2.2 Host allows
  503. // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
  504. // as part of reg-name.
  505. // We add : because we include :port as part of host.
  506. // We add [ ] because we include [ipv6]:port as part of host.
  507. // We add < > because they're the only characters left that
  508. // we could possibly allow, and Parse will reject them if we
  509. // escape them (because hosts can't use %-encoding for
  510. // ASCII bytes).
  511. switch c {
  512. case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']', '<', '>', '"':
  513. return false
  514. }
  515. }
  516. if c == '-' || c == '_' || c == '.' || c == '~' { // §2.3 Unreserved characters (mark)
  517. return false
  518. }
  519. // Everything else must be escaped.
  520. return true
  521. }
  522. func ishex(c byte) bool {
  523. return hex2intTable[c] < 16
  524. }
  525. func unhex(c byte) byte {
  526. return hex2intTable[c] & 15
  527. }
  528. // validOptionalPort reports whether port is either an empty string
  529. // or matches /^:\d*$/.
  530. func validOptionalPort(port []byte) bool {
  531. if len(port) == 0 {
  532. return true
  533. }
  534. if port[0] != ':' {
  535. return false
  536. }
  537. for _, b := range port[1:] {
  538. if b < '0' || b > '9' {
  539. return false
  540. }
  541. }
  542. return true
  543. }
  544. func normalizePath(dst, src []byte) []byte {
  545. dst = dst[:0]
  546. dst = addLeadingSlash(dst, src)
  547. dst = decodeArgAppendNoPlus(dst, src)
  548. // remove duplicate slashes
  549. b := dst
  550. bSize := len(b)
  551. for {
  552. n := bytes.Index(b, strSlashSlash)
  553. if n < 0 {
  554. break
  555. }
  556. b = b[n:]
  557. copy(b, b[1:])
  558. b = b[:len(b)-1]
  559. bSize--
  560. }
  561. dst = dst[:bSize]
  562. // remove /./ parts
  563. b = dst
  564. for {
  565. n := bytes.Index(b, strSlashDotSlash)
  566. if n < 0 {
  567. break
  568. }
  569. nn := n + len(strSlashDotSlash) - 1
  570. copy(b[n:], b[nn:])
  571. b = b[:len(b)-nn+n]
  572. }
  573. // remove /foo/../ parts
  574. for {
  575. n := bytes.Index(b, strSlashDotDotSlash)
  576. if n < 0 {
  577. break
  578. }
  579. nn := bytes.LastIndexByte(b[:n], '/')
  580. if nn < 0 {
  581. nn = 0
  582. }
  583. n += len(strSlashDotDotSlash) - 1
  584. copy(b[nn:], b[n:])
  585. b = b[:len(b)-n+nn]
  586. }
  587. // remove trailing /foo/..
  588. n := bytes.LastIndex(b, strSlashDotDot)
  589. if n >= 0 && n+len(strSlashDotDot) == len(b) {
  590. nn := bytes.LastIndexByte(b[:n], '/')
  591. if nn < 0 {
  592. return append(dst[:0], strSlash...)
  593. }
  594. b = b[:nn+1]
  595. }
  596. if filepath.Separator == '\\' {
  597. // remove \.\ parts
  598. for {
  599. n := bytes.Index(b, strBackSlashDotBackSlash)
  600. if n < 0 {
  601. break
  602. }
  603. nn := n + len(strSlashDotSlash) - 1
  604. copy(b[n:], b[nn:])
  605. b = b[:len(b)-nn+n]
  606. }
  607. // remove /foo/..\ parts
  608. for {
  609. n := bytes.Index(b, strSlashDotDotBackSlash)
  610. if n < 0 {
  611. break
  612. }
  613. nn := bytes.LastIndexByte(b[:n], '/')
  614. if nn < 0 {
  615. nn = 0
  616. }
  617. nn++
  618. n += len(strSlashDotDotBackSlash)
  619. copy(b[nn:], b[n:])
  620. b = b[:len(b)-n+nn]
  621. }
  622. // remove /foo\..\ parts
  623. for {
  624. n := bytes.Index(b, strBackSlashDotDotBackSlash)
  625. if n < 0 {
  626. break
  627. }
  628. nn := bytes.LastIndexByte(b[:n], '/')
  629. if nn < 0 {
  630. nn = 0
  631. }
  632. n += len(strBackSlashDotDotBackSlash) - 1
  633. copy(b[nn:], b[n:])
  634. b = b[:len(b)-n+nn]
  635. }
  636. // remove trailing \foo\..
  637. n := bytes.LastIndex(b, strBackSlashDotDot)
  638. if n >= 0 && n+len(strSlashDotDot) == len(b) {
  639. nn := bytes.LastIndexByte(b[:n], '/')
  640. if nn < 0 {
  641. return append(dst[:0], strSlash...)
  642. }
  643. b = b[:nn+1]
  644. }
  645. }
  646. return b
  647. }
  648. // RequestURI returns RequestURI - i.e. URI without Scheme and Host.
  649. func (u *URI) RequestURI() []byte {
  650. var dst []byte
  651. if u.DisablePathNormalizing {
  652. dst = u.requestURI[:0]
  653. dst = append(dst, u.PathOriginal()...)
  654. } else {
  655. dst = appendQuotedPath(u.requestURI[:0], u.Path())
  656. }
  657. if u.parsedQueryArgs && u.queryArgs.Len() > 0 {
  658. dst = append(dst, '?')
  659. dst = u.queryArgs.AppendBytes(dst)
  660. } else if len(u.queryString) > 0 {
  661. dst = append(dst, '?')
  662. dst = append(dst, u.queryString...)
  663. }
  664. u.requestURI = dst
  665. return u.requestURI
  666. }
  667. // LastPathSegment returns the last part of uri path after '/'.
  668. //
  669. // Examples:
  670. //
  671. // - For /foo/bar/baz.html path returns baz.html.
  672. // - For /foo/bar/ returns empty byte slice.
  673. // - For /foobar.js returns foobar.js.
  674. //
  675. // The returned bytes are valid until the next URI method call.
  676. func (u *URI) LastPathSegment() []byte {
  677. path := u.Path()
  678. n := bytes.LastIndexByte(path, '/')
  679. if n < 0 {
  680. return path
  681. }
  682. return path[n+1:]
  683. }
  684. // Update updates uri.
  685. //
  686. // The following newURI types are accepted:
  687. //
  688. // - Absolute, i.e. http://foobar.com/aaa/bb?cc . In this case the original
  689. // uri is replaced by newURI.
  690. // - Absolute without scheme, i.e. //foobar.com/aaa/bb?cc. In this case
  691. // the original scheme is preserved.
  692. // - Missing host, i.e. /aaa/bb?cc . In this case only RequestURI part
  693. // of the original uri is replaced.
  694. // - Relative path, i.e. xx?yy=abc . In this case the original RequestURI
  695. // is updated according to the new relative path.
  696. func (u *URI) Update(newURI string) {
  697. u.UpdateBytes(s2b(newURI))
  698. }
  699. // UpdateBytes updates uri.
  700. //
  701. // The following newURI types are accepted:
  702. //
  703. // - Absolute, i.e. http://foobar.com/aaa/bb?cc . In this case the original
  704. // uri is replaced by newURI.
  705. // - Absolute without scheme, i.e. //foobar.com/aaa/bb?cc. In this case
  706. // the original scheme is preserved.
  707. // - Missing host, i.e. /aaa/bb?cc . In this case only RequestURI part
  708. // of the original uri is replaced.
  709. // - Relative path, i.e. xx?yy=abc . In this case the original RequestURI
  710. // is updated according to the new relative path.
  711. func (u *URI) UpdateBytes(newURI []byte) {
  712. u.requestURI = u.updateBytes(newURI, u.requestURI)
  713. }
  714. func (u *URI) updateBytes(newURI, buf []byte) []byte {
  715. if len(newURI) == 0 {
  716. return buf
  717. }
  718. n := bytes.Index(newURI, strSlashSlash)
  719. if n >= 0 {
  720. // absolute uri
  721. var b [32]byte
  722. schemeOriginal := b[:0]
  723. if len(u.scheme) > 0 {
  724. schemeOriginal = append([]byte(nil), u.scheme...)
  725. }
  726. if err := u.Parse(nil, newURI); err != nil {
  727. return nil
  728. }
  729. if len(schemeOriginal) > 0 && len(u.scheme) == 0 {
  730. u.scheme = append(u.scheme[:0], schemeOriginal...)
  731. }
  732. return buf
  733. }
  734. if newURI[0] == '/' {
  735. // uri without host
  736. buf = u.appendSchemeHost(buf[:0])
  737. buf = append(buf, newURI...)
  738. if err := u.Parse(nil, buf); err != nil {
  739. return nil
  740. }
  741. return buf
  742. }
  743. // relative path
  744. switch newURI[0] {
  745. case '?':
  746. // query string only update
  747. u.SetQueryStringBytes(newURI[1:])
  748. return append(buf[:0], u.FullURI()...)
  749. case '#':
  750. // update only hash
  751. u.SetHashBytes(newURI[1:])
  752. return append(buf[:0], u.FullURI()...)
  753. default:
  754. // update the last path part after the slash
  755. path := u.Path()
  756. n = bytes.LastIndexByte(path, '/')
  757. if n < 0 {
  758. panic(fmt.Sprintf("BUG: path must contain at least one slash: %q %q", u.Path(), newURI))
  759. }
  760. buf = u.appendSchemeHost(buf[:0])
  761. buf = appendQuotedPath(buf, path[:n+1])
  762. buf = append(buf, newURI...)
  763. if err := u.Parse(nil, buf); err != nil {
  764. return nil
  765. }
  766. return buf
  767. }
  768. }
  769. // FullURI returns full uri in the form {Scheme}://{Host}{RequestURI}#{Hash}.
  770. //
  771. // The returned bytes are valid until the next URI method call.
  772. func (u *URI) FullURI() []byte {
  773. u.fullURI = u.AppendBytes(u.fullURI[:0])
  774. return u.fullURI
  775. }
  776. // AppendBytes appends full uri to dst and returns the extended dst.
  777. func (u *URI) AppendBytes(dst []byte) []byte {
  778. dst = u.appendSchemeHost(dst)
  779. dst = append(dst, u.RequestURI()...)
  780. if len(u.hash) > 0 {
  781. dst = append(dst, '#')
  782. dst = append(dst, u.hash...)
  783. }
  784. return dst
  785. }
  786. func (u *URI) appendSchemeHost(dst []byte) []byte {
  787. dst = append(dst, u.Scheme()...)
  788. dst = append(dst, strColonSlashSlash...)
  789. return append(dst, u.Host()...)
  790. }
  791. // WriteTo writes full uri to w.
  792. //
  793. // WriteTo implements io.WriterTo interface.
  794. func (u *URI) WriteTo(w io.Writer) (int64, error) {
  795. n, err := w.Write(u.FullURI())
  796. return int64(n), err
  797. }
  798. // String returns full uri.
  799. func (u *URI) String() string {
  800. return string(u.FullURI())
  801. }
  802. func splitHostURI(host, uri []byte) ([]byte, []byte, []byte) {
  803. n := bytes.Index(uri, strSlashSlash)
  804. if n < 0 {
  805. return strHTTP, host, uri
  806. }
  807. scheme := uri[:n]
  808. if bytes.IndexByte(scheme, '/') >= 0 {
  809. return strHTTP, host, uri
  810. }
  811. if len(scheme) > 0 && scheme[len(scheme)-1] == ':' {
  812. scheme = scheme[:len(scheme)-1]
  813. }
  814. n += len(strSlashSlash)
  815. uri = uri[n:]
  816. n = bytes.IndexByte(uri, '/')
  817. nq := bytes.IndexByte(uri, '?')
  818. if nq >= 0 && (n < 0 || nq < n) {
  819. // A hack for urls like foobar.com?a=b/xyz
  820. n = nq
  821. }
  822. nh := bytes.IndexByte(uri, '#')
  823. if nh >= 0 && (n < 0 || nh < n) {
  824. // A hack for urls like foobar.com#abc.com
  825. n = nh
  826. }
  827. if n < 0 {
  828. return scheme, uri, strSlash
  829. }
  830. return scheme, uri[:n], uri[n:]
  831. }
  832. // QueryArgs returns query args.
  833. //
  834. // The returned args are valid until the next URI method call.
  835. func (u *URI) QueryArgs() *Args {
  836. u.parseQueryArgs()
  837. return &u.queryArgs
  838. }
  839. func (u *URI) parseQueryArgs() {
  840. if u.parsedQueryArgs {
  841. return
  842. }
  843. u.queryArgs.ParseBytes(u.queryString)
  844. u.parsedQueryArgs = true
  845. }
  846. // stringContainsCTLByte reports whether s contains any ASCII control character.
  847. func stringContainsCTLByte(s []byte) bool {
  848. for i := 0; i < len(s); i++ {
  849. b := s[i]
  850. if b < ' ' || b == 0x7f {
  851. return true
  852. }
  853. }
  854. return false
  855. }