httpsfv.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. // Copyright 2025 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package httpsfv provides functionality for dealing with HTTP Structured
  5. // Field Values.
  6. package httpsfv
  7. import (
  8. "slices"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "unicode/utf8"
  13. )
  14. func isLCAlpha(b byte) bool {
  15. return (b >= 'a' && b <= 'z')
  16. }
  17. func isAlpha(b byte) bool {
  18. return isLCAlpha(b) || (b >= 'A' && b <= 'Z')
  19. }
  20. func isDigit(b byte) bool {
  21. return b >= '0' && b <= '9'
  22. }
  23. func isVChar(b byte) bool {
  24. return b >= 0x21 && b <= 0x7e
  25. }
  26. func isSP(b byte) bool {
  27. return b == 0x20
  28. }
  29. func isTChar(b byte) bool {
  30. if isAlpha(b) || isDigit(b) {
  31. return true
  32. }
  33. return slices.Contains([]byte{'!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '_', '`', '|', '~'}, b)
  34. }
  35. func countLeftWhitespace(s string) int {
  36. i := 0
  37. for _, ch := range []byte(s) {
  38. if ch != ' ' && ch != '\t' {
  39. break
  40. }
  41. i++
  42. }
  43. return i
  44. }
  45. // https://www.rfc-editor.org/rfc/rfc4648#section-8.
  46. func decOctetHex(ch1, ch2 byte) (ch byte, ok bool) {
  47. decBase16 := func(in byte) (out byte, ok bool) {
  48. if !isDigit(in) && !(in >= 'a' && in <= 'f') {
  49. return 0, false
  50. }
  51. if isDigit(in) {
  52. return in - '0', true
  53. }
  54. return in - 'a' + 10, true
  55. }
  56. if ch1, ok = decBase16(ch1); !ok {
  57. return 0, ok
  58. }
  59. if ch2, ok = decBase16(ch2); !ok {
  60. return 0, ok
  61. }
  62. return ch1<<4 | ch2, true
  63. }
  64. // ParseList parses a list from a given HTTP Structured Field Values.
  65. //
  66. // Given an HTTP SFV string that represents a list, it will call the given
  67. // function using each of the members and parameters contained in the list.
  68. // This allows the caller to extract information out of the list.
  69. //
  70. // This function will return once it encounters the end of the string, or
  71. // something that is not a list. If it cannot consume the entire given
  72. // string, the ok value returned will be false.
  73. //
  74. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-list.
  75. func ParseList(s string, f func(member, param string)) (ok bool) {
  76. for len(s) != 0 {
  77. var member, param string
  78. if len(s) != 0 && s[0] == '(' {
  79. if member, s, ok = consumeBareInnerList(s, nil); !ok {
  80. return ok
  81. }
  82. } else {
  83. if member, s, ok = consumeBareItem(s); !ok {
  84. return ok
  85. }
  86. }
  87. if param, s, ok = consumeParameter(s, nil); !ok {
  88. return ok
  89. }
  90. if f != nil {
  91. f(member, param)
  92. }
  93. s = s[countLeftWhitespace(s):]
  94. if len(s) == 0 {
  95. break
  96. }
  97. if s[0] != ',' {
  98. return false
  99. }
  100. s = s[1:]
  101. s = s[countLeftWhitespace(s):]
  102. if len(s) == 0 {
  103. return false
  104. }
  105. }
  106. return true
  107. }
  108. // consumeBareInnerList consumes an inner list
  109. // (https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-inner-list),
  110. // except for the inner list's top-most parameter.
  111. // For example, given `(a;b c;d);e`, it will consume only `(a;b c;d)`.
  112. func consumeBareInnerList(s string, f func(bareItem, param string)) (consumed, rest string, ok bool) {
  113. if len(s) == 0 || s[0] != '(' {
  114. return "", s, false
  115. }
  116. rest = s[1:]
  117. for len(rest) != 0 {
  118. var bareItem, param string
  119. rest = rest[countLeftWhitespace(rest):]
  120. if len(rest) != 0 && rest[0] == ')' {
  121. rest = rest[1:]
  122. break
  123. }
  124. if bareItem, rest, ok = consumeBareItem(rest); !ok {
  125. return "", s, ok
  126. }
  127. if param, rest, ok = consumeParameter(rest, nil); !ok {
  128. return "", s, ok
  129. }
  130. if len(rest) == 0 || (rest[0] != ')' && !isSP(rest[0])) {
  131. return "", s, false
  132. }
  133. if f != nil {
  134. f(bareItem, param)
  135. }
  136. }
  137. return s[:len(s)-len(rest)], rest, true
  138. }
  139. // ParseBareInnerList parses a bare inner list from a given HTTP Structured
  140. // Field Values.
  141. //
  142. // We define a bare inner list as an inner list
  143. // (https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-inner-list),
  144. // without the top-most parameter of the inner list. For example, given the
  145. // inner list `(a;b c;d);e`, the bare inner list would be `(a;b c;d)`.
  146. //
  147. // Given an HTTP SFV string that represents a bare inner list, it will call the
  148. // given function using each of the bare item and parameter within the bare
  149. // inner list. This allows the caller to extract information out of the bare
  150. // inner list.
  151. //
  152. // This function will return once it encounters the end of the bare inner list,
  153. // or something that is not a bare inner list. If it cannot consume the entire
  154. // given string, the ok value returned will be false.
  155. func ParseBareInnerList(s string, f func(bareItem, param string)) (ok bool) {
  156. _, rest, ok := consumeBareInnerList(s, f)
  157. return rest == "" && ok
  158. }
  159. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-item.
  160. func consumeItem(s string, f func(bareItem, param string)) (consumed, rest string, ok bool) {
  161. var bareItem, param string
  162. if bareItem, rest, ok = consumeBareItem(s); !ok {
  163. return "", s, ok
  164. }
  165. if param, rest, ok = consumeParameter(rest, nil); !ok {
  166. return "", s, ok
  167. }
  168. if f != nil {
  169. f(bareItem, param)
  170. }
  171. return s[:len(s)-len(rest)], rest, true
  172. }
  173. // ParseItem parses an item from a given HTTP Structured Field Values.
  174. //
  175. // Given an HTTP SFV string that represents an item, it will call the given
  176. // function once, with the bare item and the parameter of the item. This allows
  177. // the caller to extract information out of the item.
  178. //
  179. // This function will return once it encounters the end of the string, or
  180. // something that is not an item. If it cannot consume the entire given
  181. // string, the ok value returned will be false.
  182. //
  183. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-item.
  184. func ParseItem(s string, f func(bareItem, param string)) (ok bool) {
  185. _, rest, ok := consumeItem(s, f)
  186. return rest == "" && ok
  187. }
  188. // ParseDictionary parses a dictionary from a given HTTP Structured Field
  189. // Values.
  190. //
  191. // Given an HTTP SFV string that represents a dictionary, it will call the
  192. // given function using each of the keys, values, and parameters contained in
  193. // the dictionary. This allows the caller to extract information out of the
  194. // dictionary.
  195. //
  196. // This function will return once it encounters the end of the string, or
  197. // something that is not a dictionary. If it cannot consume the entire given
  198. // string, the ok value returned will be false.
  199. //
  200. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-dictionary.
  201. func ParseDictionary(s string, f func(key, val, param string)) (ok bool) {
  202. for len(s) != 0 {
  203. var key, val, param string
  204. val = "?1" // Default value for empty val is boolean true.
  205. if key, s, ok = consumeKey(s); !ok {
  206. return ok
  207. }
  208. if len(s) != 0 && s[0] == '=' {
  209. s = s[1:]
  210. if len(s) != 0 && s[0] == '(' {
  211. if val, s, ok = consumeBareInnerList(s, nil); !ok {
  212. return ok
  213. }
  214. } else {
  215. if val, s, ok = consumeBareItem(s); !ok {
  216. return ok
  217. }
  218. }
  219. }
  220. if param, s, ok = consumeParameter(s, nil); !ok {
  221. return ok
  222. }
  223. if f != nil {
  224. f(key, val, param)
  225. }
  226. s = s[countLeftWhitespace(s):]
  227. if len(s) == 0 {
  228. break
  229. }
  230. if s[0] == ',' {
  231. s = s[1:]
  232. }
  233. s = s[countLeftWhitespace(s):]
  234. if len(s) == 0 {
  235. return false
  236. }
  237. }
  238. return true
  239. }
  240. // https://www.rfc-editor.org/rfc/rfc9651.html#parse-param.
  241. func consumeParameter(s string, f func(key, val string)) (consumed, rest string, ok bool) {
  242. rest = s
  243. for len(rest) != 0 {
  244. var key, val string
  245. val = "?1" // Default value for empty val is boolean true.
  246. if rest[0] != ';' {
  247. break
  248. }
  249. rest = rest[1:]
  250. rest = rest[countLeftWhitespace(rest):]
  251. key, rest, ok = consumeKey(rest)
  252. if !ok {
  253. return "", s, ok
  254. }
  255. if len(rest) != 0 && rest[0] == '=' {
  256. rest = rest[1:]
  257. val, rest, ok = consumeBareItem(rest)
  258. if !ok {
  259. return "", s, ok
  260. }
  261. }
  262. if f != nil {
  263. f(key, val)
  264. }
  265. }
  266. return s[:len(s)-len(rest)], rest, true
  267. }
  268. // ParseParameter parses a parameter from a given HTTP Structured Field Values.
  269. //
  270. // Given an HTTP SFV string that represents a parameter, it will call the given
  271. // function using each of the keys and values contained in the parameter. This
  272. // allows the caller to extract information out of the parameter.
  273. //
  274. // This function will return once it encounters the end of the string, or
  275. // something that is not a parameter. If it cannot consume the entire given
  276. // string, the ok value returned will be false.
  277. //
  278. // https://www.rfc-editor.org/rfc/rfc9651.html#parse-param.
  279. func ParseParameter(s string, f func(key, val string)) (ok bool) {
  280. _, rest, ok := consumeParameter(s, f)
  281. return rest == "" && ok
  282. }
  283. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-key.
  284. func consumeKey(s string) (consumed, rest string, ok bool) {
  285. if len(s) == 0 || (!isLCAlpha(s[0]) && s[0] != '*') {
  286. return "", s, false
  287. }
  288. i := 0
  289. for _, ch := range []byte(s) {
  290. if !isLCAlpha(ch) && !isDigit(ch) && !slices.Contains([]byte("_-.*"), ch) {
  291. break
  292. }
  293. i++
  294. }
  295. return s[:i], s[i:], true
  296. }
  297. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-integer-or-decim.
  298. func consumeIntegerOrDecimal(s string) (consumed, rest string, ok bool) {
  299. var i, signOffset, periodIndex int
  300. var isDecimal bool
  301. if i < len(s) && s[i] == '-' {
  302. i++
  303. signOffset++
  304. }
  305. if i >= len(s) {
  306. return "", s, false
  307. }
  308. if !isDigit(s[i]) {
  309. return "", s, false
  310. }
  311. for i < len(s) {
  312. ch := s[i]
  313. if isDigit(ch) {
  314. i++
  315. continue
  316. }
  317. if !isDecimal && ch == '.' {
  318. if i-signOffset > 12 {
  319. return "", s, false
  320. }
  321. periodIndex = i
  322. isDecimal = true
  323. i++
  324. continue
  325. }
  326. break
  327. }
  328. if !isDecimal && i-signOffset > 15 {
  329. return "", s, false
  330. }
  331. if isDecimal {
  332. if i-signOffset > 16 {
  333. return "", s, false
  334. }
  335. if s[i-1] == '.' {
  336. return "", s, false
  337. }
  338. if i-periodIndex-1 > 3 {
  339. return "", s, false
  340. }
  341. }
  342. return s[:i], s[i:], true
  343. }
  344. // ParseInteger parses an integer from a given HTTP Structured Field Values.
  345. //
  346. // The entire HTTP SFV string must consist of a valid integer. It returns the
  347. // parsed integer and an ok boolean value, indicating success or not.
  348. //
  349. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-integer-or-decim.
  350. func ParseInteger(s string) (parsed int64, ok bool) {
  351. if _, rest, ok := consumeIntegerOrDecimal(s); !ok || rest != "" {
  352. return 0, false
  353. }
  354. if n, err := strconv.ParseInt(s, 10, 64); err == nil {
  355. return n, true
  356. }
  357. return 0, false
  358. }
  359. // ParseDecimal parses a decimal from a given HTTP Structured Field Values.
  360. //
  361. // The entire HTTP SFV string must consist of a valid decimal. It returns the
  362. // parsed decimal and an ok boolean value, indicating success or not.
  363. //
  364. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-integer-or-decim.
  365. func ParseDecimal(s string) (parsed float64, ok bool) {
  366. if _, rest, ok := consumeIntegerOrDecimal(s); !ok || rest != "" {
  367. return 0, false
  368. }
  369. if !strings.Contains(s, ".") {
  370. return 0, false
  371. }
  372. if n, err := strconv.ParseFloat(s, 64); err == nil {
  373. return n, true
  374. }
  375. return 0, false
  376. }
  377. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-string.
  378. func consumeString(s string) (consumed, rest string, ok bool) {
  379. if len(s) == 0 || s[0] != '"' {
  380. return "", s, false
  381. }
  382. for i := 1; i < len(s); i++ {
  383. switch ch := s[i]; ch {
  384. case '\\':
  385. if i+1 >= len(s) {
  386. return "", s, false
  387. }
  388. i++
  389. if ch = s[i]; ch != '"' && ch != '\\' {
  390. return "", s, false
  391. }
  392. case '"':
  393. return s[:i+1], s[i+1:], true
  394. default:
  395. if !isVChar(ch) && !isSP(ch) {
  396. return "", s, false
  397. }
  398. }
  399. }
  400. return "", s, false
  401. }
  402. // ParseString parses a Go string from a given HTTP Structured Field Values.
  403. //
  404. // The entire HTTP SFV string must consist of a valid string. It returns the
  405. // parsed string and an ok boolean value, indicating success or not.
  406. //
  407. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-string.
  408. func ParseString(s string) (parsed string, ok bool) {
  409. if _, rest, ok := consumeString(s); !ok || rest != "" {
  410. return "", false
  411. }
  412. return s[1 : len(s)-1], true
  413. }
  414. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-token
  415. func consumeToken(s string) (consumed, rest string, ok bool) {
  416. if len(s) == 0 || (!isAlpha(s[0]) && s[0] != '*') {
  417. return "", s, false
  418. }
  419. i := 0
  420. for _, ch := range []byte(s) {
  421. if !isTChar(ch) && !slices.Contains([]byte(":/"), ch) {
  422. break
  423. }
  424. i++
  425. }
  426. return s[:i], s[i:], true
  427. }
  428. // ParseToken parses a token from a given HTTP Structured Field Values.
  429. //
  430. // The entire HTTP SFV string must consist of a valid token. It returns the
  431. // parsed token and an ok boolean value, indicating success or not.
  432. //
  433. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-token
  434. func ParseToken(s string) (parsed string, ok bool) {
  435. if _, rest, ok := consumeToken(s); !ok || rest != "" {
  436. return "", false
  437. }
  438. return s, true
  439. }
  440. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-byte-sequence.
  441. func consumeByteSequence(s string) (consumed, rest string, ok bool) {
  442. if len(s) == 0 || s[0] != ':' {
  443. return "", s, false
  444. }
  445. for i := 1; i < len(s); i++ {
  446. if ch := s[i]; ch == ':' {
  447. return s[:i+1], s[i+1:], true
  448. }
  449. if ch := s[i]; !isAlpha(ch) && !isDigit(ch) && !slices.Contains([]byte("+/="), ch) {
  450. return "", s, false
  451. }
  452. }
  453. return "", s, false
  454. }
  455. // ParseByteSequence parses a byte sequence from a given HTTP Structured Field
  456. // Values.
  457. //
  458. // The entire HTTP SFV string must consist of a valid byte sequence. It returns
  459. // the parsed byte sequence and an ok boolean value, indicating success or not.
  460. //
  461. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-byte-sequence.
  462. func ParseByteSequence(s string) (parsed []byte, ok bool) {
  463. if _, rest, ok := consumeByteSequence(s); !ok || rest != "" {
  464. return nil, false
  465. }
  466. return []byte(s[1 : len(s)-1]), true
  467. }
  468. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-boolean.
  469. func consumeBoolean(s string) (consumed, rest string, ok bool) {
  470. if len(s) >= 2 && (s[:2] == "?0" || s[:2] == "?1") {
  471. return s[:2], s[2:], true
  472. }
  473. return "", s, false
  474. }
  475. // ParseBoolean parses a boolean from a given HTTP Structured Field Values.
  476. //
  477. // The entire HTTP SFV string must consist of a valid boolean. It returns the
  478. // parsed boolean and an ok boolean value, indicating success or not.
  479. //
  480. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-boolean.
  481. func ParseBoolean(s string) (parsed bool, ok bool) {
  482. if _, rest, ok := consumeBoolean(s); !ok || rest != "" {
  483. return false, false
  484. }
  485. return s == "?1", true
  486. }
  487. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-date.
  488. func consumeDate(s string) (consumed, rest string, ok bool) {
  489. if len(s) == 0 || s[0] != '@' {
  490. return "", s, false
  491. }
  492. if _, rest, ok = consumeIntegerOrDecimal(s[1:]); !ok {
  493. return "", s, ok
  494. }
  495. consumed = s[:len(s)-len(rest)]
  496. if slices.Contains([]byte(consumed), '.') {
  497. return "", s, false
  498. }
  499. return consumed, rest, ok
  500. }
  501. // ParseDate parses a date from a given HTTP Structured Field Values.
  502. //
  503. // The entire HTTP SFV string must consist of a valid date. It returns the
  504. // parsed date and an ok boolean value, indicating success or not.
  505. //
  506. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-date.
  507. func ParseDate(s string) (parsed time.Time, ok bool) {
  508. if _, rest, ok := consumeDate(s); !ok || rest != "" {
  509. return time.Time{}, false
  510. }
  511. if n, ok := ParseInteger(s[1:]); !ok {
  512. return time.Time{}, false
  513. } else {
  514. return time.Unix(n, 0), true
  515. }
  516. }
  517. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-display-string.
  518. func consumeDisplayString(s string) (consumed, rest string, ok bool) {
  519. // To prevent excessive allocation, especially when input is large, we
  520. // maintain a buffer of 4 bytes to keep track of the last rune we
  521. // encounter. This way, we can validate that the display string conforms to
  522. // UTF-8 without actually building the whole string.
  523. var lastRune [4]byte
  524. var runeLen int
  525. isPartOfValidRune := func(ch byte) bool {
  526. lastRune[runeLen] = ch
  527. runeLen++
  528. if utf8.FullRune(lastRune[:runeLen]) {
  529. r, s := utf8.DecodeRune(lastRune[:runeLen])
  530. if r == utf8.RuneError {
  531. return false
  532. }
  533. copy(lastRune[:], lastRune[s:runeLen])
  534. runeLen -= s
  535. return true
  536. }
  537. return runeLen <= 4
  538. }
  539. if len(s) <= 1 || s[:2] != `%"` {
  540. return "", s, false
  541. }
  542. i := 2
  543. for i < len(s) {
  544. ch := s[i]
  545. if !isVChar(ch) && !isSP(ch) {
  546. return "", s, false
  547. }
  548. switch ch {
  549. case '"':
  550. if runeLen > 0 {
  551. return "", s, false
  552. }
  553. return s[:i+1], s[i+1:], true
  554. case '%':
  555. if i+2 >= len(s) {
  556. return "", s, false
  557. }
  558. if ch, ok = decOctetHex(s[i+1], s[i+2]); !ok {
  559. return "", s, ok
  560. }
  561. if ok = isPartOfValidRune(ch); !ok {
  562. return "", s, ok
  563. }
  564. i += 3
  565. default:
  566. if ok = isPartOfValidRune(ch); !ok {
  567. return "", s, ok
  568. }
  569. i++
  570. }
  571. }
  572. return "", s, false
  573. }
  574. // ParseDisplayString parses a display string from a given HTTP Structured
  575. // Field Values.
  576. //
  577. // The entire HTTP SFV string must consist of a valid display string. It
  578. // returns the parsed display string and an ok boolean value, indicating
  579. // success or not.
  580. //
  581. // https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-display-string.
  582. func ParseDisplayString(s string) (parsed string, ok bool) {
  583. if _, rest, ok := consumeDisplayString(s); !ok || rest != "" {
  584. return "", false
  585. }
  586. // consumeDisplayString() already validates that we have a valid display
  587. // string. Therefore, we can just construct the display string, without
  588. // validating it again.
  589. s = s[2 : len(s)-1]
  590. var b strings.Builder
  591. for i := 0; i < len(s); {
  592. if s[i] == '%' {
  593. decoded, _ := decOctetHex(s[i+1], s[i+2])
  594. b.WriteByte(decoded)
  595. i += 3
  596. continue
  597. }
  598. b.WriteByte(s[i])
  599. i++
  600. }
  601. return b.String(), true
  602. }
  603. // https://www.rfc-editor.org/rfc/rfc9651.html#parse-bare-item.
  604. func consumeBareItem(s string) (consumed, rest string, ok bool) {
  605. if len(s) == 0 {
  606. return "", s, false
  607. }
  608. ch := s[0]
  609. switch {
  610. case ch == '-' || isDigit(ch):
  611. return consumeIntegerOrDecimal(s)
  612. case ch == '"':
  613. return consumeString(s)
  614. case ch == '*' || isAlpha(ch):
  615. return consumeToken(s)
  616. case ch == ':':
  617. return consumeByteSequence(s)
  618. case ch == '?':
  619. return consumeBoolean(s)
  620. case ch == '@':
  621. return consumeDate(s)
  622. case ch == '%':
  623. return consumeDisplayString(s)
  624. default:
  625. return "", s, false
  626. }
  627. }