mirror of
https://github.com/boostorg/url.git
synced 2026-01-19 04:42:15 +00:00
docs: convert qbk content to asciidoc
This commit is contained in:
committed by
Alan de Freitas
parent
e9f69ef7f0
commit
446b5343ff
154
doc/modules/ROOT/images/AuthorityDiagram.svg
Normal file
154
doc/modules/ROOT/images/AuthorityDiagram.svg
Normal file
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.2" width="116.84mm" height="25.4mm" viewBox="0 0 11684 2540" preserveAspectRatio="xMidYMid" fill-rule="evenodd" stroke-width="28.222" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" xmlns:ooo="http://xml.openoffice.org/svg/export" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:presentation="http://sun.com/xmlns/staroffice/presentation" xmlns:smil="http://www.w3.org/2001/SMIL20/" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xml:space="preserve">
|
||||
<defs class="ClipPathGroup">
|
||||
<clipPath id="presentation_clip_path" clipPathUnits="userSpaceOnUse">
|
||||
<rect x="0" y="0" width="11684" height="2540"/>
|
||||
</clipPath>
|
||||
<clipPath id="presentation_clip_path_shrink" clipPathUnits="userSpaceOnUse">
|
||||
<rect x="11" y="2" width="11661" height="2535"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<defs>
|
||||
<font id="EmbeddedFont_1" horiz-adv-x="2048">
|
||||
<font-face font-family="Liberation Sans embedded" units-per-em="2048" font-weight="normal" font-style="normal" ascent="1852" descent="423"/>
|
||||
<missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
|
||||
<glyph unicode="x" horiz-adv-x="980" d="M 801,0 L 510,444 217,0 23,0 408,556 41,1082 240,1082 510,661 778,1082 979,1082 612,558 1002,0 801,0 Z"/>
|
||||
<glyph unicode="w" horiz-adv-x="1509" d="M 1174,0 L 965,0 776,765 740,934 C 734,904 725,861 712,805 699,748 631,480 508,0 L 300,0 -3,1082 175,1082 358,347 C 363,331 377,265 401,149 L 418,223 644,1082 837,1082 1026,339 1072,149 1103,288 1308,1082 1484,1082 1174,0 Z"/>
|
||||
<glyph unicode="u" horiz-adv-x="874" d="M 314,1082 L 314,396 C 314,325 321,269 335,230 349,191 371,162 402,145 433,128 478,119 537,119 624,119 692,149 742,208 792,267 817,350 817,455 L 817,1082 997,1082 997,231 C 997,105 999,28 1003,0 L 833,0 C 832,3 832,12 831,27 830,42 830,59 829,78 828,97 826,132 825,185 L 822,185 C 781,110 733,58 679,27 624,-4 557,-20 476,-20 357,-20 271,10 216,69 161,128 133,225 133,361 L 133,1082 314,1082 Z"/>
|
||||
<glyph unicode="t" horiz-adv-x="531" d="M 554,8 C 495,-8 434,-16 372,-16 228,-16 156,66 156,229 L 156,951 31,951 31,1082 163,1082 216,1324 336,1324 336,1082 536,1082 536,951 336,951 336,268 C 336,216 345,180 362,159 379,138 408,127 450,127 474,127 509,132 554,141 L 554,8 Z"/>
|
||||
<glyph unicode="s" horiz-adv-x="927" d="M 950,299 C 950,197 912,118 835,63 758,8 650,-20 511,-20 376,-20 273,2 200,47 127,91 79,160 57,254 L 216,285 C 231,227 263,185 311,158 359,131 426,117 511,117 602,117 669,131 712,159 754,187 775,229 775,285 775,328 760,362 731,389 702,416 654,438 589,455 L 460,489 C 357,516 283,542 240,568 196,593 162,624 137,661 112,698 100,743 100,796 100,895 135,970 206,1022 276,1073 378,1099 513,1099 632,1099 727,1078 798,1036 868,994 912,927 931,834 L 769,814 C 759,862 732,899 689,925 645,950 586,963 513,963 432,963 372,951 333,926 294,901 275,864 275,814 275,783 283,758 299,738 315,718 339,701 370,687 401,673 467,654 568,629 663,605 732,583 774,563 816,542 849,520 874,495 898,470 917,442 930,410 943,377 950,340 950,299 Z"/>
|
||||
<glyph unicode="r" horiz-adv-x="530" d="M 142,0 L 142,830 C 142,906 140,990 136,1082 L 306,1082 C 311,959 314,886 314,861 L 318,861 C 347,954 380,1017 417,1051 454,1085 507,1102 575,1102 599,1102 623,1099 648,1092 L 648,927 C 624,934 592,937 552,937 477,937 420,905 381,841 342,776 322,684 322,564 L 322,0 142,0 Z"/>
|
||||
<glyph unicode="p" horiz-adv-x="927" d="M 1053,546 C 1053,169 920,-20 655,-20 488,-20 376,43 319,168 L 314,168 C 317,163 318,106 318,-2 L 318,-425 138,-425 138,861 C 138,972 136,1046 132,1082 L 306,1082 C 307,1079 308,1070 309,1054 310,1037 312,1012 314,978 315,944 316,921 316,908 L 320,908 C 352,975 394,1024 447,1055 500,1086 569,1101 655,1101 788,1101 888,1056 954,967 1020,878 1053,737 1053,546 Z M 864,542 C 864,693 844,800 803,865 762,930 698,962 609,962 538,962 482,947 442,917 401,887 371,840 350,777 329,713 318,630 318,528 318,386 341,281 386,214 431,147 505,113 607,113 696,113 762,146 803,212 844,277 864,387 864,542 Z"/>
|
||||
<glyph unicode="o" horiz-adv-x="980" d="M 1053,542 C 1053,353 1011,212 928,119 845,26 724,-20 565,-20 407,-20 288,28 207,125 126,221 86,360 86,542 86,915 248,1102 571,1102 736,1102 858,1057 936,966 1014,875 1053,733 1053,542 Z M 864,542 C 864,691 842,800 798,868 753,935 679,969 574,969 469,969 393,935 346,866 299,797 275,689 275,542 275,399 298,292 345,221 391,149 464,113 563,113 671,113 748,148 795,217 841,286 864,395 864,542 Z"/>
|
||||
<glyph unicode="m" horiz-adv-x="1457" d="M 768,0 L 768,686 C 768,791 754,863 725,903 696,943 645,963 570,963 493,963 433,934 388,875 343,816 321,734 321,627 L 321,0 142,0 142,851 C 142,977 140,1054 136,1082 L 306,1082 C 307,1079 307,1070 308,1055 309,1040 310,1024 311,1005 312,986 313,950 314,897 L 317,897 C 356,974 400,1027 450,1057 500,1087 561,1102 633,1102 715,1102 780,1086 828,1053 875,1020 908,968 927,897 L 930,897 C 967,970 1013,1022 1066,1054 1119,1086 1183,1102 1258,1102 1367,1102 1447,1072 1497,1013 1546,954 1571,856 1571,721 L 1571,0 1393,0 1393,686 C 1393,791 1379,863 1350,903 1321,943 1270,963 1195,963 1116,963 1055,934 1012,876 968,817 946,734 946,627 L 946,0 768,0 Z"/>
|
||||
<glyph unicode="l" horiz-adv-x="187" d="M 138,0 L 138,1484 318,1484 318,0 138,0 Z"/>
|
||||
<glyph unicode="h" horiz-adv-x="874" d="M 317,897 C 356,968 402,1020 457,1053 511,1086 580,1102 663,1102 780,1102 867,1073 923,1015 978,956 1006,858 1006,721 L 1006,0 825,0 825,686 C 825,762 818,819 804,856 790,893 767,920 735,937 703,954 659,963 602,963 517,963 450,934 399,875 348,816 322,737 322,638 L 322,0 142,0 142,1484 322,1484 322,1098 C 322,1057 321,1015 319,972 316,929 315,904 314,897 L 317,897 Z"/>
|
||||
<glyph unicode="e" horiz-adv-x="980" d="M 276,503 C 276,379 302,283 353,216 404,149 479,115 578,115 656,115 719,131 766,162 813,193 844,233 861,281 L 1019,236 C 954,65 807,-20 578,-20 418,-20 296,28 213,123 129,218 87,360 87,548 87,727 129,864 213,959 296,1054 416,1102 571,1102 889,1102 1048,910 1048,527 L 1048,503 276,503 Z M 862,641 C 852,755 823,838 775,891 727,943 658,969 568,969 481,969 412,940 361,882 310,823 282,743 278,641 L 862,641 Z"/>
|
||||
<glyph unicode="c" horiz-adv-x="901" d="M 275,546 C 275,402 298,295 343,226 388,157 457,122 548,122 612,122 666,139 709,174 752,209 778,262 788,334 L 970,322 C 956,218 912,135 837,73 762,11 668,-20 553,-20 402,-20 286,28 207,124 127,219 87,359 87,542 87,724 127,863 207,959 287,1054 402,1102 551,1102 662,1102 754,1073 827,1016 900,959 945,880 964,779 L 779,765 C 770,825 746,873 708,908 670,943 616,961 546,961 451,961 382,929 339,866 296,803 275,696 275,546 Z"/>
|
||||
<glyph unicode="a" horiz-adv-x="1060" d="M 414,-20 C 305,-20 224,9 169,66 114,123 87,202 87,302 87,414 124,500 198,560 271,620 390,652 554,656 L 797,660 797,719 C 797,807 778,870 741,908 704,946 645,965 565,965 484,965 426,951 389,924 352,897 330,853 323,793 L 135,810 C 166,1005 310,1102 569,1102 705,1102 807,1071 876,1009 945,946 979,856 979,738 L 979,272 C 979,219 986,179 1000,152 1014,125 1041,111 1080,111 1097,111 1117,113 1139,118 L 1139,6 C 1094,-5 1047,-10 1000,-10 933,-10 885,8 855,43 824,78 807,132 803,207 L 797,207 C 751,124 698,66 637,32 576,-3 501,-20 414,-20 Z M 455,115 C 521,115 580,130 631,160 682,190 723,231 753,284 782,336 797,390 797,445 L 797,534 600,530 C 515,529 451,520 408,504 364,488 330,463 307,430 284,397 272,353 272,299 272,240 288,195 320,163 351,131 396,115 455,115 Z"/>
|
||||
<glyph unicode="@" horiz-adv-x="1747" d="M 1902,755 C 1902,631 1883,519 1845,419 1806,318 1753,241 1685,186 1616,131 1540,104 1455,104 1389,104 1338,119 1302,148 1266,177 1248,221 1248,280 L 1251,350 1245,350 C 1201,268 1147,207 1082,166 1017,125 946,104 871,104 766,104 685,138 628,206 570,274 541,368 541,489 541,598 563,700 606,794 649,888 709,963 786,1018 863,1073 949,1101 1043,1101 1189,1101 1289,1040 1344,919 L 1350,919 1389,1079 1545,1079 1429,573 C 1404,464 1392,379 1392,320 1392,257 1419,226 1473,226 1526,226 1576,249 1621,295 1666,341 1701,404 1727,485 1753,566 1766,655 1766,753 1766,872 1740,978 1689,1071 1638,1163 1564,1234 1467,1284 1370,1333 1257,1358 1128,1358 967,1358 824,1322 700,1251 576,1180 479,1077 408,943 337,808 302,658 302,491 302,362 328,249 381,151 433,52 509,-23 608,-76 707,-129 822,-155 954,-155 1051,-155 1149,-142 1248,-117 1347,-92 1450,-51 1557,7 L 1612,-105 C 1515,-163 1411,-207 1298,-237 1185,-268 1070,-283 954,-283 793,-283 653,-251 533,-187 412,-124 320,-33 257,85 193,202 161,338 161,491 161,678 203,847 286,1000 369,1153 484,1272 631,1357 778,1442 943,1484 1126,1484 1287,1484 1425,1454 1542,1394 1659,1333 1748,1248 1810,1138 1871,1028 1902,900 1902,755 Z M 1296,747 C 1296,815 1274,870 1230,912 1186,953 1127,974 1054,974 987,974 927,953 875,911 822,868 781,810 751,735 721,660 706,578 706,491 706,411 722,348 754,303 785,258 834,235 900,235 983,235 1060,270 1129,340 1198,410 1246,497 1273,602 1288,663 1296,712 1296,747 Z"/>
|
||||
<glyph unicode=":" horiz-adv-x="239" d="M 187,875 L 187,1082 382,1082 382,875 187,875 Z M 187,0 L 187,207 382,207 382,0 187,0 Z"/>
|
||||
<glyph unicode="8" horiz-adv-x="980" d="M 1050,393 C 1050,263 1009,162 926,89 843,16 725,-20 570,-20 419,-20 302,16 217,87 132,158 89,260 89,391 89,483 115,560 168,623 221,686 288,724 370,737 L 370,741 C 293,759 233,798 189,858 144,918 122,988 122,1069 122,1176 162,1263 243,1330 323,1397 431,1430 566,1430 705,1430 814,1397 895,1332 975,1267 1015,1178 1015,1067 1015,986 993,916 948,856 903,796 842,758 765,743 L 765,739 C 855,724 925,686 975,625 1025,563 1050,486 1050,393 Z M 828,1057 C 828,1216 741,1296 566,1296 481,1296 417,1276 373,1236 328,1196 306,1136 306,1057 306,976 329,915 375,873 420,830 485,809 568,809 653,809 717,829 762,868 806,907 828,970 828,1057 Z M 863,410 C 863,497 837,563 785,608 733,652 660,674 566,674 475,674 403,650 352,603 301,555 275,489 275,406 275,212 374,115 572,115 670,115 743,139 791,186 839,233 863,307 863,410 Z"/>
|
||||
<glyph unicode="0" horiz-adv-x="980" d="M 1059,705 C 1059,470 1018,290 935,166 852,42 729,-20 567,-20 405,-20 283,42 202,165 121,288 80,468 80,705 80,947 120,1128 199,1249 278,1370 402,1430 573,1430 739,1430 862,1369 941,1247 1020,1125 1059,944 1059,705 Z M 876,705 C 876,908 853,1056 806,1147 759,1238 681,1284 573,1284 462,1284 383,1239 335,1149 286,1059 262,911 262,705 262,505 287,359 336,266 385,173 462,127 569,127 675,127 753,174 802,269 851,364 876,509 876,705 Z"/>
|
||||
<glyph unicode="/" horiz-adv-x="557" d="M 0,-20 L 411,1484 569,1484 162,-20 0,-20 Z"/>
|
||||
<glyph unicode="." horiz-adv-x="239" d="M 187,0 L 187,219 382,219 382,0 187,0 Z"/>
|
||||
</font>
|
||||
</defs>
|
||||
<defs>
|
||||
<font id="EmbeddedFont_2" horiz-adv-x="2048">
|
||||
<font-face font-family="Liberation Sans Narrow embedded" units-per-em="2048" font-weight="normal" font-style="italic" ascent="1482" descent="423"/>
|
||||
<missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
|
||||
<glyph unicode="u" horiz-adv-x="848" d="M 339,1082 L 240,446 C 236,420 232,394 228,367 224,341 222,317 222,296 222,241 234,197 257,166 280,135 317,120 369,120 404,120 438,128 470,145 501,162 530,186 556,217 582,248 604,285 622,329 640,372 654,421 662,475 L 753,1082 894,1082 766,230 C 763,208 759,184 756,159 L 745,88 737,31 C 734,15 733,5 732,0 L 593,0 C 593,3 594,12 596,27 L 603,78 C 606,96 609,115 612,135 615,155 617,172 619,185 L 613,185 C 594,154 575,125 556,100 536,75 514,53 491,36 467,18 441,4 412,-5 383,-14 351,-19 314,-19 233,-19 173,5 132,54 91,103 71,173 71,265 71,289 73,316 78,346 83,376 87,403 91,428 L 192,1082 339,1082 Z"/>
|
||||
<glyph unicode="t" horiz-adv-x="477" d="M 368,4 C 348,-2 326,-7 302,-12 277,-17 252,-20 226,-20 179,-20 143,-3 116,31 89,65 76,110 76,166 76,187 78,210 82,234 85,258 89,279 91,296 L 194,951 89,951 111,1082 214,1082 300,1324 398,1324 359,1082 523,1082 502,951 339,951 239,320 C 237,307 234,290 231,272 228,253 227,237 227,224 227,192 233,167 245,149 256,132 275,123 301,123 315,123 328,124 341,127 353,129 367,132 383,137 L 368,4 Z"/>
|
||||
<glyph unicode="s" horiz-adv-x="821" d="M 744,317 C 744,260 735,211 716,169 697,126 671,91 637,63 603,35 562,14 513,1 464,-13 410,-20 349,-20 298,-20 254,-15 216,-4 177,7 144,22 117,43 89,63 66,88 48,119 29,149 15,184 4,223 L 125,279 C 133,252 144,229 157,208 170,187 185,169 204,155 223,140 245,129 271,122 297,115 327,111 362,111 397,111 429,115 458,122 487,129 513,140 534,155 555,170 571,190 583,214 594,238 600,267 600,301 600,328 595,351 585,370 574,389 560,405 541,420 522,434 499,447 471,459 444,470 414,483 381,497 346,511 312,526 280,543 248,560 220,580 196,603 171,626 152,654 138,686 123,717 116,754 116,797 116,852 126,898 145,937 164,975 191,1006 224,1030 257,1054 295,1072 339,1083 383,1094 430,1099 479,1099 524,1099 565,1094 602,1085 639,1076 672,1061 700,1041 728,1020 751,994 769,962 787,929 799,890 806,844 L 672,819 C 660,872 637,910 604,933 571,956 526,968 469,968 440,968 413,965 388,960 362,955 340,946 321,934 302,922 286,907 275,887 264,868 258,845 258,817 258,790 263,767 274,749 285,731 299,715 318,701 337,687 360,674 386,663 386,663 416,650 474,624 505,611 537,597 569,583 602,569 631,550 657,526 682,502 703,474 720,440 736,406 744,365 744,317 Z"/>
|
||||
<glyph unicode="r" horiz-adv-x="610" d="M 589,938 C 580,941 569,944 556,947 543,950 529,951 515,951 480,951 449,939 421,914 393,889 369,858 348,820 327,782 309,740 294,694 279,649 269,605 262,564 L 175,0 28,0 157,830 C 161,853 165,877 168,900 L 178,968 188,1031 196,1082 335,1082 C 335,1067 335,1049 335,1029 L 325,969 316,910 C 313,891 311,874 309,861 L 310,861 C 327,902 343,938 360,969 377,999 394,1024 412,1044 430,1063 449,1078 470,1088 491,1097 513,1102 538,1102 544,1102 551,1102 558,1101 565,1100 572,1098 579,1097 586,1096 593,1094 600,1093 607,1091 612,1089 616,1088 L 589,938 Z"/>
|
||||
<glyph unicode="p" horiz-adv-x="954" d="M 453,-20 C 386,-20 331,-3 288,32 246,67 216,115 198,178 L 194,178 C 194,177 193,171 192,159 190,148 188,133 185,116 L 177,59 C 174,38 171,18 168,-1 L 105,-425 -42,-425 150,862 C 154,888 157,913 161,937 165,961 168,983 171,1002 174,1022 176,1039 178,1052 180,1066 182,1076 183,1082 L 328,1082 C 328,1077 327,1068 325,1056 324,1044 322,1031 319,1016 317,1001 315,986 312,969 310,952 307,937 305,923 L 308,921 C 329,952 349,979 370,1002 391,1025 413,1044 436,1059 460,1074 485,1085 513,1092 540,1099 570,1102 604,1102 649,1102 688,1094 722,1077 756,1060 785,1037 808,1006 832,975 850,938 862,895 874,851 880,802 880,748 880,715 879,678 876,639 873,599 869,558 863,516 848,421 829,340 804,273 780,205 751,149 717,106 683,63 644,31 600,11 556,-10 507,-20 453,-20 Z M 563,963 C 528,963 494,957 462,944 430,931 400,910 373,879 346,848 322,806 301,754 281,702 264,636 251,556 240,490 235,431 236,378 236,335 240,297 250,264 259,231 273,203 290,181 307,158 328,141 353,130 377,119 405,113 435,113 470,113 501,119 528,132 556,144 581,165 603,196 626,226 645,267 663,318 680,369 695,433 707,510 720,591 726,659 726,716 726,798 713,860 687,901 661,942 620,963 563,963 Z"/>
|
||||
<glyph unicode="o" horiz-adv-x="848" d="M 881,683 C 881,648 879,614 876,579 873,544 867,506 859,467 842,379 820,304 791,242 762,180 727,130 688,91 649,52 605,24 557,7 509,-11 458,-20 403,-20 350,-20 303,-10 260,10 217,29 181,58 151,96 120,133 97,179 80,234 63,288 55,350 55,419 56,450 57,483 60,516 62,549 66,584 73,620 89,704 111,776 139,837 166,897 199,947 238,986 276,1025 319,1054 368,1073 416,1092 469,1101 526,1101 584,1101 635,1092 679,1073 723,1054 760,1027 790,991 820,955 843,911 858,860 873,808 881,749 881,683 Z M 728,683 C 728,734 723,778 714,814 705,850 691,880 674,903 656,926 635,942 610,953 585,964 556,969 525,969 496,969 467,965 438,957 409,948 381,931 354,906 327,881 303,845 281,798 259,751 241,689 226,612 219,575 214,541 211,508 208,475 207,444 207,416 207,361 212,315 223,276 233,237 247,206 266,182 284,158 305,141 330,130 355,119 382,113 412,113 441,113 470,117 499,125 528,133 555,150 581,176 606,201 630,238 652,285 673,332 691,395 706,473 713,513 719,550 722,583 725,616 727,650 728,683 Z"/>
|
||||
<glyph unicode="n" horiz-adv-x="848" d="M 588,0 L 688,645 C 692,672 696,698 700,725 704,752 706,775 706,795 706,848 695,889 672,918 649,947 611,962 559,962 524,962 491,954 459,937 428,920 400,896 375,865 349,834 328,796 309,753 291,709 278,660 269,607 L 175,0 28,0 160,852 C 164,874 168,898 171,923 L 182,994 191,1051 C 194,1067 195,1077 196,1082 L 335,1082 C 335,1079 336,1069 338,1054 L 331,1004 322,945 C 319,926 317,910 314,897 L 315,897 C 334,928 353,957 373,982 392,1007 414,1029 438,1047 461,1064 487,1078 516,1087 545,1096 577,1101 614,1101 695,1101 756,1077 797,1028 838,979 858,909 858,817 858,804 856,783 851,752 846,721 842,693 838,668 L 733,0 588,0 Z"/>
|
||||
<glyph unicode="i" horiz-adv-x="398" d="M 237,1312 L 264,1484 411,1484 384,1312 237,1312 Z M 27,0 L 200,1082 347,1082 174,0 27,0 Z"/>
|
||||
<glyph unicode="h" horiz-adv-x="848" d="M 320,897 C 339,928 358,957 377,982 396,1007 418,1029 441,1047 465,1064 491,1078 519,1087 547,1096 580,1101 616,1101 696,1101 756,1077 796,1028 837,979 857,909 857,817 857,796 855,770 850,740 845,710 841,682 837,657 L 735,0 587,0 687,646 C 691,672 695,698 699,725 703,752 705,775 705,795 705,848 694,889 671,918 648,947 610,962 558,962 524,962 491,953 460,936 429,919 401,895 376,864 351,833 330,796 312,752 294,709 281,660 272,606 L 175,0 28,0 265,1484 412,1484 350,1099 C 347,1077 343,1055 340,1033 336,1011 333,990 330,972 327,953 325,937 323,924 320,911 319,902 318,897 L 320,897 Z"/>
|
||||
<glyph unicode="f" horiz-adv-x="583" d="M 356,951 L 204,0 57,0 209,951 84,951 105,1082 230,1082 249,1204 C 256,1243 264,1280 274,1314 285,1348 300,1378 319,1403 338,1428 363,1448 394,1463 425,1477 463,1484 510,1484 527,1484 545,1483 564,1481 583,1479 599,1476 612,1472 L 591,1335 C 586,1336 581,1337 574,1338 568,1339 561,1340 554,1341 547,1342 540,1342 533,1343 527,1343 521,1343 516,1343 495,1343 478,1339 464,1332 450,1325 438,1314 429,1300 420,1286 413,1269 408,1249 403,1228 398,1205 393,1179 L 377,1082 551,1082 529,951 356,951 Z"/>
|
||||
<glyph unicode="e" horiz-adv-x="821" d="M 210,503 C 207,484 206,466 205,447 204,428 203,409 203,390 203,301 221,233 258,186 294,139 348,115 421,115 452,115 480,120 505,130 530,139 553,152 574,169 594,185 612,204 628,226 643,247 656,270 667,294 L 780,231 C 767,201 750,171 730,142 710,112 686,85 657,61 628,37 593,18 552,3 511,-12 461,-20 404,-20 349,-20 301,-10 258,9 215,28 178,55 148,92 118,128 95,172 80,225 65,278 57,338 57,405 57,510 69,606 92,692 115,778 147,851 188,912 229,973 278,1020 334,1053 390,1086 451,1102 517,1102 577,1102 629,1092 674,1073 718,1054 755,1027 784,992 813,957 835,916 850,868 865,819 872,766 872,708 872,694 872,679 871,662 870,645 868,628 867,610 865,592 863,574 861,556 858,537 855,520 852,503 L 210,503 Z M 722,641 C 723,654 724,667 725,679 725,690 725,702 725,713 725,757 720,795 710,828 700,860 686,887 668,908 650,929 629,944 604,954 579,964 551,969 520,969 494,969 467,964 438,955 409,945 381,928 354,903 327,878 303,845 281,803 259,760 242,706 230,641 L 722,641 Z"/>
|
||||
</font>
|
||||
</defs>
|
||||
<defs class="TextShapeIndex">
|
||||
<g ooo:slide="id1" ooo:id-list="id3 id4 id5 id6 id7 id8 id9 id10"/>
|
||||
</defs>
|
||||
<defs class="EmbeddedBulletChars">
|
||||
<g id="bullet-char-template-57356" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 580,1141 L 1163,571 580,0 -4,571 580,1141 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-57354" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 8,1128 L 1137,1128 1137,0 8,0 8,1128 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10146" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 174,0 L 602,739 174,1481 1456,739 174,0 Z M 1358,739 L 309,1346 659,739 1358,739 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10132" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 2015,739 L 1276,0 717,0 1260,543 174,543 174,936 1260,936 717,1481 1274,1481 2015,739 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10007" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 0,-2 C -7,14 -16,27 -25,37 L 356,567 C 262,823 215,952 215,954 215,979 228,992 255,992 264,992 276,990 289,987 310,991 331,999 354,1012 L 381,999 492,748 772,1049 836,1024 860,1049 C 881,1039 901,1025 922,1006 886,937 835,863 770,784 769,783 710,716 594,584 L 774,223 C 774,196 753,168 711,139 L 727,119 C 717,90 699,76 672,76 641,76 570,178 457,381 L 164,-76 C 142,-110 111,-127 72,-127 30,-127 9,-110 8,-76 1,-67 -2,-52 -2,-32 -2,-23 -1,-13 0,-2 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10004" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 285,-33 C 182,-33 111,30 74,156 52,228 41,333 41,471 41,549 55,616 82,672 116,743 169,778 240,778 293,778 328,747 346,684 L 369,508 C 377,444 397,411 428,410 L 1163,1116 C 1174,1127 1196,1133 1229,1133 1271,1133 1292,1118 1292,1087 L 1292,965 C 1292,929 1282,901 1262,881 L 442,47 C 390,-6 338,-33 285,-33 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-9679" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 813,0 C 632,0 489,54 383,161 276,268 223,411 223,592 223,773 276,916 383,1023 489,1130 632,1184 813,1184 992,1184 1136,1130 1245,1023 1353,916 1407,772 1407,592 1407,412 1353,268 1245,161 1136,54 992,0 813,0 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-8226" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 346,457 C 273,457 209,483 155,535 101,586 74,649 74,723 74,796 101,859 155,911 209,963 273,989 346,989 419,989 480,963 531,910 582,859 608,796 608,723 608,648 583,586 532,535 482,483 420,457 346,457 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-8211" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M -4,459 L 1135,459 1135,606 -4,606 -4,459 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-61548" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 173,740 C 173,903 231,1043 346,1159 462,1274 601,1332 765,1332 928,1332 1067,1274 1183,1159 1299,1043 1357,903 1357,740 1357,577 1299,437 1183,322 1067,206 928,148 765,148 601,148 462,206 346,322 231,437 173,577 173,740 Z"/>
|
||||
</g>
|
||||
</defs>
|
||||
<g>
|
||||
<g id="id2" class="Master_Slide">
|
||||
<g id="bg-id2" class="Background"/>
|
||||
<g id="bo-id2" class="BackgroundObjects"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="SlideGroup">
|
||||
<g>
|
||||
<g id="container-id1">
|
||||
<g id="id1" class="Slide" clip-path="url(#presentation_clip_path)">
|
||||
<g class="Page">
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id3">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="5152" y="1091" width="4724" height="731"/>
|
||||
<path fill="rgb(204,255,0)" stroke="none" d="M 7514,1821 L 5152,1821 5152,1091 9875,1091 9875,1821 7514,1821 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id4">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="2168" y="1091" width="2439" height="731"/>
|
||||
<path fill="rgb(255,255,153)" stroke="none" d="M 3387,1821 L 2168,1821 2168,1091 4606,1091 4606,1821 3387,1821 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="TextShape">
|
||||
<g id="id5">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="500" y="1000" width="10713" height="879"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="564px" font-weight="400"><tspan class="TextPosition" x="750" y="1633"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">http://user:pass@www.example.com:80</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id6">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="2172" y="713" width="2418" height="434"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 4580,1137 C 4580,1033 4481,929 4381,929 L 3581,929 C 3481,929 3381,825 3381,722 3381,825 3281,929 3181,929 L 2381,929 C 2281,929 2181,1033 2181,1137"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id7">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="5163" y="690" width="4723" height="441"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 9876,1121 C 9876,1015 9680,910 9484,910 L 7917,910 C 7720,910 7524,804 7524,699 7524,804 7328,910 7132,910 L 5564,910 C 5368,910 5172,1015 5172,1121"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="TextShape">
|
||||
<g id="id8">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="2540" y="200" width="1743" height="650"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans Narrow, sans-serif" font-size="423px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="2790" y="634"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">userinfo</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="TextShape">
|
||||
<g id="id9">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="6932" y="200" width="1163" height="650"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans Narrow, sans-serif" font-size="423px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="7182" y="634"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">host</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="TextShape">
|
||||
<g id="id10">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="9773" y="200" width="1104" height="650"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans Narrow, sans-serif" font-size="423px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="10023" y="634"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">port</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 25 KiB |
152
doc/modules/ROOT/images/ClassHierarchy.svg
Normal file
152
doc/modules/ROOT/images/ClassHierarchy.svg
Normal file
@@ -0,0 +1,152 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.2" width="107.95mm" height="40.64mm" viewBox="0 0 10795 4064" preserveAspectRatio="xMidYMid" fill-rule="evenodd" stroke-width="28.222" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" xmlns:ooo="http://xml.openoffice.org/svg/export" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:presentation="http://sun.com/xmlns/staroffice/presentation" xmlns:smil="http://www.w3.org/2001/SMIL20/" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xml:space="preserve">
|
||||
<defs class="ClipPathGroup">
|
||||
<clipPath id="presentation_clip_path" clipPathUnits="userSpaceOnUse">
|
||||
<rect x="0" y="0" width="10795" height="4064"/>
|
||||
</clipPath>
|
||||
<clipPath id="presentation_clip_path_shrink" clipPathUnits="userSpaceOnUse">
|
||||
<rect x="10" y="4" width="10774" height="4056"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<defs>
|
||||
<font id="EmbeddedFont_1" horiz-adv-x="2048">
|
||||
<font-face font-family="Liberation Mono embedded" units-per-em="2048" font-weight="normal" font-style="normal" ascent="1693" descent="609"/>
|
||||
<missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
|
||||
<glyph unicode="w" horiz-adv-x="1218" d="M 1018,0 L 814,0 671,471 614,673 575,534 407,0 204,0 21,1082 199,1082 292,475 C 314,299 325,190 325,149 351,256 370,327 383,363 L 518,787 711,787 841,362 C 862,292 881,221 896,149 896,169 897,194 900,224 903,254 906,285 910,317 914,348 918,378 922,407 926,436 929,458 931,475 L 1032,1082 1208,1082 1018,0 Z"/>
|
||||
<glyph unicode="v" horiz-adv-x="1112" d="M 715,0 L 502,0 69,1082 271,1082 539,378 556,325 608,141 643,258 682,376 958,1082 1159,1082 715,0 Z"/>
|
||||
<glyph unicode="u" horiz-adv-x="874" d="M 365,1082 L 365,396 C 365,292 381,220 414,180 447,139 505,119 589,119 675,119 743,148 793,207 843,266 868,348 868,455 L 868,1082 1049,1082 1049,231 C 1049,105 1051,28 1055,0 L 885,0 C 884,3 884,12 883,27 882,42 882,59 881,78 880,97 878,132 877,185 L 874,185 C 833,110 785,58 731,27 676,-4 609,-20 528,-20 409,-20 323,10 268,69 213,128 185,225 185,361 L 185,1082 365,1082 Z"/>
|
||||
<glyph unicode="t" horiz-adv-x="821" d="M 190,940 L 190,1082 360,1082 418,1364 538,1364 538,1082 970,1082 970,940 538,940 538,288 C 538,235 552,196 581,171 609,146 655,133 720,133 809,133 908,144 1017,167 L 1017,30 C 904,-1 793,-16 682,-16 574,-16 493,7 439,53 385,98 358,170 358,269 L 358,940 190,940 Z"/>
|
||||
<glyph unicode="s" horiz-adv-x="900" d="M 1060,309 C 1060,206 1021,126 944,68 866,9 758,-20 621,-20 484,-20 379,2 308,45 236,88 189,155 167,248 L 326,279 C 339,222 366,180 408,154 449,127 520,114 621,114 801,114 891,171 891,285 891,328 875,362 842,389 809,415 759,436 692,453 516,496 404,530 357,555 310,580 273,611 248,648 223,685 210,731 210,786 210,884 245,961 316,1016 387,1071 489,1099 623,1099 740,1099 834,1077 904,1033 974,988 1018,924 1035,839 L 873,819 C 866,867 842,903 802,928 762,953 702,965 623,965 460,965 378,915 378,814 378,774 392,742 420,718 447,694 492,675 553,660 L 672,629 C 781,602 859,576 907,550 954,524 992,492 1019,453 1046,414 1060,366 1060,309 Z"/>
|
||||
<glyph unicode="r" horiz-adv-x="821" d="M 1045,918 C 970,931 900,937 833,937 726,937 639,897 573,816 507,735 474,633 474,508 L 474,0 294,0 294,701 C 294,752 290,811 281,880 272,949 259,1016 242,1082 L 413,1082 C 440,990 456,907 461,832 L 466,832 C 499,907 532,962 564,997 596,1032 634,1058 678,1076 722,1093 776,1102 839,1102 908,1102 977,1096 1045,1085 L 1045,918 Z"/>
|
||||
<glyph unicode="l" horiz-adv-x="847" d="M 835,147 L 1116,142 1116,0 746,4 C 671,17 616,47 581,94 566,114 558,169 556,258 L 556,1342 267,1342 267,1484 736,1484 736,237 C 737,207 745,185 761,170 775,157 800,150 835,147 Z M 556,142 L 556,258 556,142 Z"/>
|
||||
<glyph unicode="i" horiz-adv-x="1007" d="M 745,142 L 1125,142 1125,0 143,0 143,142 565,142 565,940 246,940 246,1082 745,1082 745,142 Z M 545,1292 L 545,1484 745,1484 745,1292 545,1292 Z"/>
|
||||
<glyph unicode="e" horiz-adv-x="954" d="M 322,503 C 322,382 349,287 403,218 456,149 530,115 623,115 692,115 752,130 804,160 855,189 890,230 907,281 L 1065,236 C 1036,153 982,90 904,46 825,2 732,-20 623,-20 466,-20 345,29 260,127 175,225 133,365 133,548 133,726 175,863 258,959 341,1054 460,1102 617,1102 774,1102 892,1054 973,959 1054,864 1094,720 1094,527 L 1094,503 322,503 Z M 619,969 C 530,969 459,940 407,882 355,823 327,743 324,641 L 908,641 C 889,860 793,969 619,969 Z"/>
|
||||
<glyph unicode="c" horiz-adv-x="980" d="M 130,542 C 130,722 173,860 259,957 345,1054 469,1102 632,1102 753,1102 853,1073 932,1015 1011,956 1059,878 1078,779 L 886,765 C 875,826 849,874 806,909 763,944 703,961 624,961 519,961 442,928 393,863 344,798 319,692 319,546 319,398 344,290 393,222 442,153 518,119 623,119 695,119 755,137 802,172 849,207 879,261 890,334 L 1080,322 C 1071,258 1047,200 1008,148 968,95 915,54 850,25 785,-5 712,-20 631,-20 468,-20 343,28 258,124 173,220 130,359 130,542 Z"/>
|
||||
<glyph unicode="b" horiz-adv-x="927" d="M 1090,546 C 1090,357 1056,215 989,121 921,27 824,-20 698,-20 535,-20 424,41 364,164 L 362,164 C 362,132 361,99 359,64 356,29 354,8 353,0 L 179,0 C 183,36 185,110 185,223 L 185,1484 365,1484 365,1061 C 365,1018 364,965 361,904 L 365,904 C 426,1037 537,1104 699,1104 960,1104 1090,918 1090,546 Z M 904,540 C 904,689 884,798 843,865 802,932 737,965 650,965 551,965 478,929 433,856 388,783 365,672 365,524 365,385 387,281 431,214 475,147 547,113 648,113 738,113 803,148 844,218 884,287 904,395 904,540 Z"/>
|
||||
<glyph unicode="a" horiz-adv-x="1059" d="M 1101,111 C 1118,111 1138,113 1160,118 L 1160,6 C 1115,-5 1068,-10 1021,-10 954,-10 906,8 876,43 845,78 828,132 824,207 L 818,207 C 775,126 724,68 665,33 606,-2 533,-20 446,-20 341,-20 261,9 208,66 155,123 128,202 128,302 128,535 279,653 582,656 L 818,660 818,719 C 818,806 800,869 765,908 730,946 673,965 596,965 517,965 461,951 426,923 391,895 371,852 364,793 L 176,810 C 207,1005 348,1102 599,1102 732,1102 833,1071 900,1009 967,946 1000,856 1000,738 L 1000,272 C 1000,219 1007,179 1021,152 1035,125 1062,111 1101,111 Z M 492,117 C 556,117 613,132 662,163 711,194 750,235 777,286 804,337 818,390 818,445 L 818,534 628,530 C 549,529 489,520 448,504 407,488 375,464 352,431 329,398 317,354 317,299 317,244 332,200 362,167 391,134 435,117 492,117 Z"/>
|
||||
<glyph unicode="_" horiz-adv-x="1271" d="M -5,-220 L -5,-124 1233,-124 1233,-220 -5,-220 Z"/>
|
||||
</font>
|
||||
</defs>
|
||||
<defs class="TextShapeIndex">
|
||||
<g ooo:slide="id1" ooo:id-list="id3 id4 id5 id6 id7 id8 id9 id10 id11 id12"/>
|
||||
</defs>
|
||||
<defs class="EmbeddedBulletChars">
|
||||
<g id="bullet-char-template-57356" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 580,1141 L 1163,571 580,0 -4,571 580,1141 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-57354" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 8,1128 L 1137,1128 1137,0 8,0 8,1128 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10146" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 174,0 L 602,739 174,1481 1456,739 174,0 Z M 1358,739 L 309,1346 659,739 1358,739 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10132" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 2015,739 L 1276,0 717,0 1260,543 174,543 174,936 1260,936 717,1481 1274,1481 2015,739 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10007" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 0,-2 C -7,14 -16,27 -25,37 L 356,567 C 262,823 215,952 215,954 215,979 228,992 255,992 264,992 276,990 289,987 310,991 331,999 354,1012 L 381,999 492,748 772,1049 836,1024 860,1049 C 881,1039 901,1025 922,1006 886,937 835,863 770,784 769,783 710,716 594,584 L 774,223 C 774,196 753,168 711,139 L 727,119 C 717,90 699,76 672,76 641,76 570,178 457,381 L 164,-76 C 142,-110 111,-127 72,-127 30,-127 9,-110 8,-76 1,-67 -2,-52 -2,-32 -2,-23 -1,-13 0,-2 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10004" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 285,-33 C 182,-33 111,30 74,156 52,228 41,333 41,471 41,549 55,616 82,672 116,743 169,778 240,778 293,778 328,747 346,684 L 369,508 C 377,444 397,411 428,410 L 1163,1116 C 1174,1127 1196,1133 1229,1133 1271,1133 1292,1118 1292,1087 L 1292,965 C 1292,929 1282,901 1262,881 L 442,47 C 390,-6 338,-33 285,-33 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-9679" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 813,0 C 632,0 489,54 383,161 276,268 223,411 223,592 223,773 276,916 383,1023 489,1130 632,1184 813,1184 992,1184 1136,1130 1245,1023 1353,916 1407,772 1407,592 1407,412 1353,268 1245,161 1136,54 992,0 813,0 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-8226" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 346,457 C 273,457 209,483 155,535 101,586 74,649 74,723 74,796 101,859 155,911 209,963 273,989 346,989 419,989 480,963 531,910 582,859 608,796 608,723 608,648 583,586 532,535 482,483 420,457 346,457 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-8211" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M -4,459 L 1135,459 1135,606 -4,606 -4,459 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-61548" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 173,740 C 173,903 231,1043 346,1159 462,1274 601,1332 765,1332 928,1332 1067,1274 1183,1159 1299,1043 1357,903 1357,740 1357,577 1299,437 1183,322 1067,206 928,148 765,148 601,148 462,206 346,322 231,437 173,577 173,740 Z"/>
|
||||
</g>
|
||||
</defs>
|
||||
<g>
|
||||
<g id="id2" class="Master_Slide">
|
||||
<g id="bg-id2" class="Background"/>
|
||||
<g id="bo-id2" class="BackgroundObjects"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="SlideGroup">
|
||||
<g>
|
||||
<g id="container-id1">
|
||||
<g id="id1" class="Slide" clip-path="url(#presentation_clip_path)">
|
||||
<g class="Page">
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id3">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="-1" y="0" width="10796" height="4065"/>
|
||||
<path fill="rgb(255,255,255)" stroke="none" d="M 5397,4064 L -1,4064 -1,0 10794,0 10794,4064 5397,4064 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id4">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="2913" y="290" width="3512" height="654"/>
|
||||
<path fill="rgb(221,221,221)" stroke="none" d="M 4669,934 L 2922,934 2922,299 6415,299 6415,934 4669,934 Z"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 4669,934 L 2922,934 2922,299 6415,299 6415,934 4669,934 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Mono, monospace" font-size="353px" font-weight="400"><tspan class="TextPosition" x="3293" y="710"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">url_view_base</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id5">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4820" y="1560" width="3511" height="654"/>
|
||||
<path fill="rgb(221,221,221)" stroke="none" d="M 6575,2204 L 4829,2204 4829,1569 8321,1569 8321,2204 6575,2204 Z"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 6575,2204 L 4829,2204 4829,1569 8321,1569 8321,2204 6575,2204 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Mono, monospace" font-size="353px" font-weight="400"><tspan class="TextPosition" x="5729" y="1980"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">url_base</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id6">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="2596" y="2830" width="3511" height="654"/>
|
||||
<path fill="rgb(255,255,255)" stroke="none" d="M 4351,3474 L 2605,3474 2605,2839 6097,2839 6097,3474 4351,3474 Z"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 4351,3474 L 2605,3474 2605,2839 6097,2839 6097,3474 4351,3474 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Mono, monospace" font-size="353px" font-weight="400"><tspan class="TextPosition" x="4034" y="3250"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">url</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id7">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="6724" y="2830" width="3511" height="654"/>
|
||||
<path fill="rgb(255,255,255)" stroke="none" d="M 8479,3474 L 6733,3474 6733,2839 10225,2839 10225,3474 8479,3474 Z"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 8479,3474 L 6733,3474 6733,2839 10225,2839 10225,3474 8479,3474 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Mono, monospace" font-size="353px" font-weight="400"><tspan class="TextPosition" x="7421" y="3250"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">static_url</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id8">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="691" y="1560" width="3511" height="654"/>
|
||||
<path fill="rgb(255,255,255)" stroke="none" d="M 2446,2204 L 700,2204 700,1569 4192,1569 4192,2204 2446,2204 Z"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 2446,2204 L 700,2204 700,1569 4192,1569 4192,2204 2446,2204 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Mono, monospace" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1600" y="1980"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">url_view</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id9">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="2437" y="926" width="2242" height="654"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 4669,935 L 2446,1570"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id10">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4660" y="926" width="1925" height="654"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 4669,935 L 6575,1570"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id11">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4342" y="2196" width="2243" height="654"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 6575,2205 L 4351,2840"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id12">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="6566" y="2196" width="1923" height="654"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 6575,2205 L 8479,2840"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 15 KiB |
518
doc/modules/ROOT/images/HelpCard.svg
Normal file
518
doc/modules/ROOT/images/HelpCard.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 154 KiB |
145
doc/modules/ROOT/images/PartsDiagram.svg
Normal file
145
doc/modules/ROOT/images/PartsDiagram.svg
Normal file
@@ -0,0 +1,145 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.2" width="165.1mm" height="16.51mm" viewBox="0 0 16510 1651" preserveAspectRatio="xMidYMid" fill-rule="evenodd" stroke-width="28.222" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" xmlns:ooo="http://xml.openoffice.org/svg/export" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:presentation="http://sun.com/xmlns/staroffice/presentation" xmlns:smil="http://www.w3.org/2001/SMIL20/" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xml:space="preserve">
|
||||
<defs class="ClipPathGroup">
|
||||
<clipPath id="presentation_clip_path" clipPathUnits="userSpaceOnUse">
|
||||
<rect x="0" y="0" width="16510" height="1651"/>
|
||||
</clipPath>
|
||||
<clipPath id="presentation_clip_path_shrink" clipPathUnits="userSpaceOnUse">
|
||||
<rect x="16" y="1" width="16477" height="1648"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<defs>
|
||||
<font id="EmbeddedFont_1" horiz-adv-x="2048">
|
||||
<font-face font-family="Liberation Sans embedded" units-per-em="2048" font-weight="normal" font-style="italic" ascent="1852" descent="423"/>
|
||||
<missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
|
||||
<glyph unicode="y" horiz-adv-x="1271" d="M 16,-425 C -32,-425 -76,-420 -116,-411 L -85,-277 C -55,-282 -29,-285 -8,-285 55,-285 111,-264 160,-221 208,-178 255,-116 302,-35 L 329,12 112,1082 295,1082 407,484 C 417,431 426,374 435,314 444,253 448,214 449,196 456,211 464,229 475,250 486,271 637,549 928,1082 L 1127,1082 501,0 C 427,-129 368,-219 323,-270 278,-322 231,-361 182,-386 133,-412 77,-425 16,-425 Z"/>
|
||||
<glyph unicode="u" horiz-adv-x="1033" d="M 415,1082 L 289,437 C 277,378 271,328 271,287 271,176 331,120 450,120 534,120 608,152 672,216 736,280 779,367 800,476 L 918,1082 1098,1082 932,231 C 919,168 906,91 893,0 L 723,0 C 723,7 727,33 734,78 741,122 746,158 751,185 L 748,185 C 693,108 637,55 582,26 526,-4 460,-19 383,-19 284,-19 210,5 161,54 111,103 86,173 86,265 86,308 93,362 107,429 L 234,1082 415,1082 Z"/>
|
||||
<glyph unicode="t" horiz-adv-x="557" d="M 275,-20 C 218,-20 174,-3 142,31 109,65 93,110 93,166 93,203 98,246 108,296 L 234,951 109,951 135,1082 262,1082 367,1324 487,1324 440,1082 640,1082 614,951 414,951 289,306 C 281,266 277,234 277,211 277,152 307,123 367,123 395,123 428,128 467,137 L 448,4 C 382,-12 324,-20 275,-20 Z"/>
|
||||
<glyph unicode="s" horiz-adv-x="1006" d="M 907,317 C 907,209 866,126 783,68 700,9 581,-20 425,-20 309,-20 217,0 149,39 80,78 32,139 5,223 L 152,279 C 174,220 208,178 255,151 301,124 363,111 441,111 536,111 609,127 658,160 707,192 732,239 732,301 732,342 715,377 681,405 647,432 575,463 465,497 380,525 316,552 273,579 230,606 198,637 175,673 152,708 141,750 141,797 141,894 180,968 257,1021 334,1073 443,1099 584,1099 820,1099 953,1014 982,844 L 819,819 C 804,872 777,910 736,933 695,956 641,968 572,968 489,968 426,955 382,929 337,902 315,865 315,817 315,789 322,765 336,746 350,727 370,710 397,695 423,680 484,657 579,627 664,600 728,573 771,546 814,519 847,486 871,449 895,412 907,368 907,317 Z"/>
|
||||
<glyph unicode="r" horiz-adv-x="742" d="M 718,938 C 689,947 659,951 628,951 558,951 495,914 439,841 382,768 344,675 324,564 L 214,0 34,0 196,830 221,968 239,1082 409,1082 374,861 378,861 C 422,950 465,1012 508,1048 551,1084 600,1102 656,1102 687,1102 718,1097 751,1088 L 718,938 Z"/>
|
||||
<glyph unicode="q" horiz-adv-x="1086" d="M 401,-21 C 296,-21 215,11 157,74 98,137 69,223 69,333 69,468 90,600 131,727 172,854 229,948 304,1009 378,1070 473,1101 588,1101 670,1101 737,1084 789,1049 840,1014 877,966 898,903 L 903,903 C 910,939 919,978 930,1021 941,1064 948,1089 952,1096 L 1125,1096 C 1110,1044 1088,946 1060,801 L 822,-425 642,-425 727,14 759,160 755,160 C 706,97 655,51 601,22 547,-7 480,-21 401,-21 Z M 453,118 C 519,118 576,132 623,159 670,186 709,226 742,281 775,335 800,403 819,485 838,566 847,639 847,704 847,787 826,852 784,899 741,945 682,968 607,968 526,968 461,944 414,896 367,847 329,768 300,659 271,549 257,451 257,365 257,283 273,221 304,180 335,139 385,118 453,118 Z"/>
|
||||
<glyph unicode="p" horiz-adv-x="1139" d="M 554,-20 C 472,-20 405,-3 354,32 302,67 265,115 244,178 L 239,178 C 239,171 236,149 231,113 225,77 191,-102 128,-425 L -51,-425 198,861 C 213,935 225,1009 233,1082 L 400,1082 C 400,1064 398,1037 394,1000 389,963 386,936 383,921 L 387,921 C 436,984 487,1030 541,1059 595,1088 662,1102 741,1102 846,1102 927,1071 986,1008 1044,945 1073,858 1073,748 1073,613 1053,482 1012,355 971,228 913,133 839,72 764,11 669,-20 554,-20 Z M 689,963 C 623,963 567,950 520,923 473,896 433,855 400,801 367,746 342,678 323,597 304,515 295,442 295,377 295,294 316,229 359,183 401,136 460,113 535,113 618,113 683,138 731,189 779,239 817,319 844,429 871,538 885,634 885,716 885,798 869,860 838,901 807,942 757,963 689,963 Z"/>
|
||||
<glyph unicode="o" horiz-adv-x="1033" d="M 1074,683 C 1074,596 1061,506 1034,413 1007,319 969,240 920,175 870,110 809,61 737,29 665,-4 583,-20 491,-20 360,-20 257,19 181,98 105,177 67,284 67,419 70,555 94,676 141,781 188,886 252,966 335,1020 418,1074 520,1101 642,1101 782,1101 889,1065 963,992 1037,919 1074,816 1074,683 Z M 888,683 C 888,874 805,969 640,969 550,969 478,946 424,900 369,853 327,783 297,689 267,595 252,504 252,416 252,317 273,242 316,191 359,139 421,113 502,113 571,113 626,125 668,148 709,171 746,207 777,256 808,305 834,367 854,443 873,519 885,599 888,683 Z"/>
|
||||
<glyph unicode="n" horiz-adv-x="1033" d="M 717,0 L 843,645 C 855,704 861,754 861,795 861,906 801,962 682,962 598,962 524,930 460,866 396,802 353,715 332,606 L 214,0 34,0 200,851 C 213,914 226,991 239,1082 L 409,1082 C 409,1075 406,1049 399,1005 392,960 386,924 381,897 L 384,897 C 439,974 495,1027 551,1057 606,1086 672,1101 749,1101 848,1101 922,1077 972,1028 1021,979 1046,909 1046,817 1046,774 1039,720 1025,653 L 898,0 717,0 Z"/>
|
||||
<glyph unicode="m" horiz-adv-x="1589" d="M 660,0 L 784,634 C 801,717 809,775 809,808 809,858 796,896 771,923 746,949 704,962 647,962 570,962 502,929 445,863 387,797 349,711 331,604 L 213,0 34,0 200,851 C 213,914 226,991 239,1082 L 409,1082 C 409,1075 406,1049 399,1005 392,960 386,924 381,897 L 384,897 C 433,973 482,1026 531,1056 580,1086 638,1101 706,1101 787,1101 851,1081 898,1042 945,1002 974,944 983,869 1038,956 1093,1016 1147,1050 1200,1084 1262,1101 1331,1101 1421,1101 1490,1077 1539,1028 1587,979 1611,909 1611,817 1611,774 1604,720 1590,653 L 1463,0 1285,0 1409,634 C 1426,717 1434,775 1434,808 1434,858 1421,896 1396,923 1371,949 1329,962 1272,962 1195,962 1127,930 1070,865 1013,800 975,714 956,607 L 838,0 660,0 Z"/>
|
||||
<glyph unicode="i" horiz-adv-x="478" d="M 287,1312 L 321,1484 501,1484 467,1312 287,1312 Z M 33,0 L 243,1082 423,1082 212,0 33,0 Z"/>
|
||||
<glyph unicode="h" horiz-adv-x="1033" d="M 383,897 C 438,974 494,1027 550,1057 605,1086 671,1101 748,1101 847,1101 921,1077 971,1028 1020,979 1045,909 1045,817 1045,774 1038,720 1024,653 L 897,0 716,0 842,645 C 854,704 860,754 860,795 860,906 800,962 681,962 597,962 523,930 459,866 395,802 352,715 331,606 L 213,0 34,0 322,1484 502,1484 427,1098 C 415,1031 399,964 380,897 L 383,897 Z"/>
|
||||
<glyph unicode="g" horiz-adv-x="1139" d="M 397,-425 C 171,-425 40,-341 4,-173 L 167,-131 C 190,-236 268,-288 401,-288 496,-288 569,-263 621,-214 673,-165 710,-85 731,27 L 765,201 763,201 C 722,142 685,99 654,73 622,47 586,27 547,13 507,-1 461,-8 410,-8 308,-8 226,26 164,93 101,160 70,248 70,359 70,448 83,543 108,646 133,749 167,834 210,902 253,970 306,1020 368,1053 430,1085 503,1101 588,1101 669,1101 737,1082 793,1044 848,1006 884,957 900,897 L 902,897 C 907,922 915,957 927,1004 939,1050 947,1076 950,1082 L 1121,1082 1102,1000 1072,858 911,31 C 879,-130 822,-247 739,-318 656,-389 542,-425 397,-425 Z M 259,373 C 259,292 277,231 312,189 347,146 398,125 466,125 538,125 603,151 662,204 721,256 766,328 799,419 831,510 847,605 847,704 847,787 826,852 783,899 740,945 682,968 607,968 547,968 497,956 457,931 417,906 383,868 356,815 329,762 306,692 287,605 268,517 259,440 259,373 Z"/>
|
||||
<glyph unicode="f" horiz-adv-x="689" d="M 434,951 L 249,0 69,0 254,951 102,951 128,1082 280,1082 303,1204 C 318,1279 339,1335 364,1372 389,1409 422,1437 463,1456 504,1475 557,1484 622,1484 671,1484 713,1480 746,1472 L 720,1335 675,1341 629,1343 C 587,1343 555,1332 533,1311 510,1289 492,1245 479,1179 L 460,1082 671,1082 645,951 434,951 Z"/>
|
||||
<glyph unicode="e" horiz-adv-x="1033" d="M 256,503 C 252,480 249,442 247,390 247,301 269,233 314,186 358,139 425,115 514,115 579,115 637,131 690,163 743,195 784,239 813,294 L 951,231 C 902,144 841,80 766,40 691,0 600,-20 493,-20 359,-20 255,17 181,92 106,166 69,270 69,405 69,539 93,659 140,766 187,872 254,955 340,1014 426,1073 523,1102 630,1102 767,1102 873,1068 949,999 1025,930 1063,833 1063,708 1063,638 1055,570 1039,503 L 256,503 Z M 880,641 L 884,713 C 884,796 863,859 820,903 777,947 715,969 634,969 545,969 470,941 409,884 348,827 305,746 280,641 L 880,641 Z"/>
|
||||
<glyph unicode="c" horiz-adv-x="980" d="M 469,122 C 606,122 702,199 758,352 L 914,303 C 833,88 684,-20 465,-20 337,-20 239,16 170,89 101,162 67,264 67,395 67,528 91,652 140,767 188,882 252,966 332,1021 411,1075 509,1102 625,1102 738,1102 827,1074 893,1017 958,960 994,883 1001,784 L 824,759 C 820,824 800,874 764,909 728,944 680,961 619,961 535,961 467,939 415,894 363,849 323,777 294,679 265,581 251,484 251,389 251,211 324,122 469,122 Z"/>
|
||||
<glyph unicode="a" horiz-adv-x="1060" d="M 927,-10 C 865,-10 820,3 792,29 763,54 749,92 749,143 L 754,207 748,207 C 693,123 635,64 576,31 517,-3 445,-20 361,-20 268,-20 192,8 134,64 75,120 46,191 46,278 46,401 90,495 179,558 267,621 408,654 601,657 L 833,660 C 846,725 852,768 852,787 852,848 834,893 799,922 764,951 715,965 652,965 573,965 513,951 472,923 431,894 402,851 384,793 L 206,822 C 236,920 288,991 363,1036 437,1080 537,1102 662,1102 776,1102 866,1075 933,1022 999,969 1032,897 1032,807 1032,764 1026,712 1013,650 L 939,272 C 932,240 928,211 928,184 928,135 955,111 1009,111 1027,111 1047,113 1069,118 L 1055,6 C 1011,-5 968,-10 927,-10 Z M 809,536 L 610,532 C 531,530 468,523 423,511 378,498 343,483 318,464 293,445 273,421 259,392 244,363 237,327 237,286 237,236 253,195 286,164 318,133 360,117 411,117 476,117 534,131 586,159 638,186 681,222 715,267 749,312 771,360 782,411 L 809,536 Z"/>
|
||||
</font>
|
||||
</defs>
|
||||
<defs>
|
||||
<font id="EmbeddedFont_2" horiz-adv-x="2048">
|
||||
<font-face font-family="Liberation Sans embedded" units-per-em="2048" font-weight="bold" font-style="normal" ascent="1852" descent="423"/>
|
||||
<missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
|
||||
<glyph unicode="”" horiz-adv-x="742" d="M 872,1217 C 872,1136 864,1065 847,1004 830,942 802,884 763,831 L 579,831 C 668,943 712,1049 712,1149 L 585,1149 585,1409 872,1409 872,1217 Z M 442,1217 C 442,1134 434,1062 417,1003 400,943 372,886 333,831 L 151,831 C 238,943 282,1049 282,1149 L 155,1149 155,1409 442,1409 442,1217 Z"/>
|
||||
<glyph unicode="“" horiz-adv-x="742" d="M 579,831 L 579,1026 C 579,1109 588,1180 606,1241 624,1302 652,1358 690,1409 L 872,1409 C 831,1357 799,1303 776,1248 753,1192 741,1140 741,1092 L 868,1092 868,831 579,831 Z M 151,831 L 151,1026 C 151,1107 160,1178 177,1240 194,1301 222,1358 259,1409 L 442,1409 C 401,1357 369,1303 346,1248 323,1192 311,1140 311,1092 L 438,1092 438,831 151,831 Z"/>
|
||||
<glyph unicode="?" horiz-adv-x="1060" d="M 1133,1026 C 1133,961 1119,903 1090,852 1061,801 1006,747 927,690 L 851,635 C 806,602 772,569 750,536 727,503 715,466 713,426 L 446,426 C 450,494 469,555 504,608 538,661 588,711 655,758 726,807 777,851 806,889 835,926 850,968 850,1014 850,1073 831,1119 793,1153 754,1187 700,1204 629,1204 562,1204 505,1184 460,1145 414,1106 387,1054 379,989 L 94,1001 C 112,1136 168,1242 261,1317 354,1392 476,1430 625,1430 783,1430 907,1394 998,1323 1088,1251 1133,1152 1133,1026 Z M 438,0 L 438,270 727,270 727,0 438,0 Z"/>
|
||||
<glyph unicode=":" horiz-adv-x="319" d="M 197,752 L 197,1034 485,1034 485,752 197,752 Z M 197,0 L 197,281 485,281 485,0 197,0 Z"/>
|
||||
<glyph unicode="/" horiz-adv-x="557" d="M 20,-41 L 311,1484 549,1484 263,-41 20,-41 Z"/>
|
||||
<glyph unicode="#" horiz-adv-x="1086" d="M 909,862 L 840,530 1055,530 1055,381 809,381 727,0 571,0 651,381 344,381 264,0 111,0 190,381 35,381 35,530 223,530 293,862 86,862 86,1010 324,1010 408,1395 561,1395 479,1010 786,1010 870,1395 1026,1395 942,1010 1106,1010 1106,862 909,862 Z M 449,862 L 377,530 686,530 756,862 449,862 Z"/>
|
||||
<glyph unicode=" " horiz-adv-x="556"/>
|
||||
</font>
|
||||
</defs>
|
||||
<defs class="TextShapeIndex">
|
||||
<g ooo:slide="id1" ooo:id-list="id3 id4 id5 id6 id7 id8"/>
|
||||
</defs>
|
||||
<defs class="EmbeddedBulletChars">
|
||||
<g id="bullet-char-template-57356" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 580,1141 L 1163,571 580,0 -4,571 580,1141 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-57354" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 8,1128 L 1137,1128 1137,0 8,0 8,1128 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10146" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 174,0 L 602,739 174,1481 1456,739 174,0 Z M 1358,739 L 309,1346 659,739 1358,739 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10132" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 2015,739 L 1276,0 717,0 1260,543 174,543 174,936 1260,936 717,1481 1274,1481 2015,739 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10007" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 0,-2 C -7,14 -16,27 -25,37 L 356,567 C 262,823 215,952 215,954 215,979 228,992 255,992 264,992 276,990 289,987 310,991 331,999 354,1012 L 381,999 492,748 772,1049 836,1024 860,1049 C 881,1039 901,1025 922,1006 886,937 835,863 770,784 769,783 710,716 594,584 L 774,223 C 774,196 753,168 711,139 L 727,119 C 717,90 699,76 672,76 641,76 570,178 457,381 L 164,-76 C 142,-110 111,-127 72,-127 30,-127 9,-110 8,-76 1,-67 -2,-52 -2,-32 -2,-23 -1,-13 0,-2 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10004" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 285,-33 C 182,-33 111,30 74,156 52,228 41,333 41,471 41,549 55,616 82,672 116,743 169,778 240,778 293,778 328,747 346,684 L 369,508 C 377,444 397,411 428,410 L 1163,1116 C 1174,1127 1196,1133 1229,1133 1271,1133 1292,1118 1292,1087 L 1292,965 C 1292,929 1282,901 1262,881 L 442,47 C 390,-6 338,-33 285,-33 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-9679" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 813,0 C 632,0 489,54 383,161 276,268 223,411 223,592 223,773 276,916 383,1023 489,1130 632,1184 813,1184 992,1184 1136,1130 1245,1023 1353,916 1407,772 1407,592 1407,412 1353,268 1245,161 1136,54 992,0 813,0 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-8226" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 346,457 C 273,457 209,483 155,535 101,586 74,649 74,723 74,796 101,859 155,911 209,963 273,989 346,989 419,989 480,963 531,910 582,859 608,796 608,723 608,648 583,586 532,535 482,483 420,457 346,457 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-8211" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M -4,459 L 1135,459 1135,606 -4,606 -4,459 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-61548" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 173,740 C 173,903 231,1043 346,1159 462,1274 601,1332 765,1332 928,1332 1067,1274 1183,1159 1299,1043 1357,903 1357,740 1357,577 1299,437 1183,322 1067,206 928,148 765,148 601,148 462,206 346,322 231,437 173,577 173,740 Z"/>
|
||||
</g>
|
||||
</defs>
|
||||
<g>
|
||||
<g id="id2" class="Master_Slide">
|
||||
<g id="bg-id2" class="Background"/>
|
||||
<g id="bo-id2" class="BackgroundObjects"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="SlideGroup">
|
||||
<g>
|
||||
<g id="container-id1">
|
||||
<g id="id1" class="Slide" clip-path="url(#presentation_clip_path)">
|
||||
<g class="Page">
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id3">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="0" y="-1" width="16511" height="1652"/>
|
||||
<path fill="rgb(255,255,255)" stroke="none" d="M 8255,1650 L 0,1650 0,-1 16510,-1 16510,1650 8255,1650 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id4">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="12990" y="290" width="3195" height="997"/>
|
||||
<path fill="rgb(255,237,182)" stroke="none" d="M 13162,299 L 13162,299 C 13133,299 13105,307 13080,321 13056,335 13035,356 13021,381 13007,405 12999,433 12999,462 L 12999,1114 12999,1114 C 12999,1143 13007,1171 13021,1196 13035,1220 13056,1241 13080,1255 13105,1269 13133,1277 13162,1277 L 16012,1277 16012,1277 C 16041,1277 16069,1269 16094,1255 16118,1241 16139,1220 16153,1196 16167,1171 16175,1143 16175,1114 L 16175,462 16175,462 16175,462 C 16175,433 16167,405 16153,381 16139,356 16118,335 16094,321 16069,307 16041,299 16012,299 L 13162,299 Z"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 13162,299 L 13162,299 C 13133,299 13105,307 13080,321 13056,335 13035,356 13021,381 13007,405 12999,433 12999,462 L 12999,1114 12999,1114 C 12999,1143 13007,1171 13021,1196 13035,1220 13056,1241 13080,1255 13105,1269 13133,1277 13162,1277 L 16012,1277 16012,1277 C 16041,1277 16069,1269 16094,1255 16118,1241 16139,1220 16153,1196 16167,1171 16175,1143 16175,1114 L 16175,462 16175,462 16175,462 C 16175,433 16167,405 16153,381 16139,356 16118,335 16094,321 16069,307 16041,299 16012,299 L 13162,299 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="388px" font-weight="700"><tspan class="TextPosition" x="13458" y="955"><tspan fill="rgb(51,51,51)" stroke="none" style="white-space: pre">“</tspan><tspan fill="rgb(51,51,51)" stroke="none" style="white-space: pre">#” </tspan><tspan font-style="italic" font-weight="400" fill="rgb(51,51,51)" stroke="none" style="white-space: pre">fragment</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id5">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="9814" y="290" width="3196" height="997"/>
|
||||
<path fill="rgb(255,220,255)" stroke="none" d="M 9987,299 L 9987,299 C 9958,299 9930,307 9906,321 9881,335 9860,356 9846,381 9832,405 9824,433 9824,462 L 9824,1114 9824,1114 C 9824,1143 9832,1171 9846,1196 9860,1220 9881,1241 9906,1255 9930,1269 9958,1277 9987,1277 L 12837,1277 12837,1277 C 12866,1277 12894,1269 12919,1255 12943,1241 12964,1220 12978,1196 12992,1171 13000,1143 13000,1114 L 13000,462 13000,462 13000,462 C 13000,433 12992,405 12978,381 12964,356 12943,335 12919,321 12894,307 12866,299 12837,299 L 9987,299 Z"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 9987,299 L 9987,299 C 9958,299 9930,307 9906,321 9881,335 9860,356 9846,381 9832,405 9824,433 9824,462 L 9824,1114 9824,1114 C 9824,1143 9832,1171 9846,1196 9860,1220 9881,1241 9906,1255 9930,1269 9958,1277 9987,1277 L 12837,1277 12837,1277 C 12866,1277 12894,1269 12919,1255 12943,1241 12964,1220 12978,1196 12992,1171 13000,1143 13000,1114 L 13000,462 13000,462 13000,462 C 13000,433 12992,405 12978,381 12964,356 12943,335 12919,321 12894,307 12866,299 12837,299 L 9987,299 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="388px" font-weight="700"><tspan class="TextPosition" x="10556" y="955"><tspan fill="rgb(51,51,51)" stroke="none" style="white-space: pre">“</tspan><tspan fill="rgb(51,51,51)" stroke="none" style="white-space: pre">?” </tspan><tspan font-style="italic" font-weight="400" fill="rgb(51,51,51)" stroke="none" style="white-space: pre">query</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id6">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="6640" y="290" width="3195" height="997"/>
|
||||
<path fill="rgb(193,255,255)" stroke="none" d="M 6812,299 L 6812,299 C 6783,299 6755,307 6731,321 6706,335 6685,356 6671,381 6657,405 6649,433 6649,462 L 6649,1114 6649,1114 C 6649,1143 6657,1171 6671,1196 6685,1220 6706,1241 6731,1255 6755,1269 6783,1277 6812,1277 L 9662,1277 9662,1277 C 9691,1277 9719,1269 9744,1255 9768,1241 9789,1220 9803,1196 9817,1171 9825,1143 9825,1114 L 9825,462 9825,462 9825,462 C 9825,433 9817,405 9803,381 9789,356 9768,335 9744,321 9719,307 9691,299 9662,299 L 6812,299 Z"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 6812,299 L 6812,299 C 6783,299 6755,307 6731,321 6706,335 6685,356 6671,381 6657,405 6649,433 6649,462 L 6649,1114 6649,1114 C 6649,1143 6657,1171 6671,1196 6685,1220 6706,1241 6731,1255 6755,1269 6783,1277 6812,1277 L 9662,1277 9662,1277 C 9691,1277 9719,1269 9744,1255 9768,1241 9789,1220 9803,1196 9817,1171 9825,1143 9825,1114 L 9825,462 9825,462 9825,462 C 9825,433 9817,405 9803,381 9789,356 9768,335 9744,321 9719,307 9691,299 9662,299 L 6812,299 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="388px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="7858" y="955"><tspan fill="rgb(51,51,51)" stroke="none" style="white-space: pre">path</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id7">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="289" y="297" width="3196" height="998"/>
|
||||
<path fill="rgb(255,255,177)" stroke="none" d="M 462,306 L 462,306 C 433,306 405,314 380,328 356,342 335,363 321,388 307,412 299,440 299,469 L 299,1121 299,1121 C 299,1150 307,1178 321,1203 335,1227 356,1248 381,1262 405,1276 433,1284 462,1284 L 3312,1284 3312,1284 C 3341,1284 3369,1276 3394,1262 3418,1248 3439,1227 3453,1203 3467,1178 3475,1150 3475,1121 L 3475,469 3475,469 3475,469 C 3475,440 3467,412 3453,387 3439,363 3418,342 3394,328 3369,314 3341,306 3312,306 L 462,306 Z"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 462,306 L 462,306 C 433,306 405,314 380,328 356,342 335,363 321,388 307,412 299,440 299,469 L 299,1121 299,1121 C 299,1150 307,1178 321,1203 335,1227 356,1248 381,1262 405,1276 433,1284 462,1284 L 3312,1284 3312,1284 C 3341,1284 3369,1276 3394,1262 3418,1248 3439,1227 3453,1203 3467,1178 3475,1150 3475,1121 L 3475,469 3475,469 3475,469 C 3475,440 3467,412 3453,387 3439,363 3418,342 3394,328 3369,314 3341,306 3312,306 L 462,306 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="388px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="890" y="962"><tspan fill="rgb(51,51,51)" stroke="none" style="white-space: pre">scheme</tspan><tspan font-style="normal" font-weight="700" fill="rgb(51,51,51)" stroke="none" style="white-space: pre"> “:”</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id8">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="3465" y="290" width="3196" height="997"/>
|
||||
<path fill="rgb(215,255,195)" stroke="none" d="M 3637,299 L 3637,299 C 3608,299 3580,307 3555,321 3531,335 3510,356 3496,381 3482,405 3474,433 3474,462 L 3474,1114 3474,1114 C 3474,1143 3482,1171 3496,1196 3510,1220 3531,1241 3555,1255 3580,1269 3608,1277 3637,1277 L 6487,1277 6487,1277 C 6516,1277 6544,1269 6569,1255 6593,1241 6614,1220 6628,1196 6642,1171 6650,1143 6650,1114 L 6650,462 6650,462 6650,462 C 6650,433 6642,405 6628,381 6614,356 6593,335 6569,321 6544,307 6516,299 6487,299 L 3637,299 Z"/>
|
||||
<path fill="none" stroke="rgb(0,0,0)" stroke-width="18" stroke-linejoin="round" d="M 3637,299 L 3637,299 C 3608,299 3580,307 3555,321 3531,335 3510,356 3496,381 3482,405 3474,433 3474,462 L 3474,1114 3474,1114 C 3474,1143 3482,1171 3496,1196 3510,1220 3531,1241 3555,1255 3580,1269 3608,1277 3637,1277 L 6487,1277 6487,1277 C 6516,1277 6544,1269 6569,1255 6593,1241 6614,1220 6628,1196 6642,1171 6650,1143 6650,1114 L 6650,462 6650,462 6650,462 C 6650,433 6642,405 6628,381 6614,356 6593,335 6569,321 6544,307 6516,299 6487,299 L 3637,299 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="388px" font-weight="700"><tspan class="TextPosition" x="3955" y="955"><tspan fill="rgb(51,51,51)" stroke="none" style="white-space: pre">“</tspan><tspan fill="rgb(51,51,51)" stroke="none" style="white-space: pre">//” </tspan><tspan font-style="italic" font-weight="400" fill="rgb(51,51,51)" stroke="none" style="white-space: pre">authority</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 24 KiB |
BIN
doc/modules/ROOT/images/repo-logo.png
Normal file
BIN
doc/modules/ROOT/images/repo-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
@@ -1,22 +1,29 @@
|
||||
* xref:quicklook.adoc[Quick Look]
|
||||
* xref:urls/index.adoc[URLs]
|
||||
** xref:urls/parsing.adoc[Parsing]
|
||||
** xref:urls/containers.adoc[Containers]
|
||||
** xref:urls/segments.adoc[Segments]
|
||||
** xref:urls/params.adoc[Params]
|
||||
** xref:urls/normalization.adoc[Normalization]
|
||||
** xref:urls/stringtoken.adoc[String Token]
|
||||
** xref:urls/percent-encoding.adoc[Percent Encoding]
|
||||
** xref:urls/formatting.adoc[Formatting]
|
||||
* xref:grammar/index.adoc[Grammar]
|
||||
** xref:grammar/rules.adoc[Parse Rules]
|
||||
** xref:grammar/charset.adoc[Character Sets]
|
||||
** xref:grammar/combinators.adoc[Compound Rules]
|
||||
** xref:grammar/range.adoc[Ranges]
|
||||
** xref:grammar/rfc3986.adoc[RFC 3986]
|
||||
* xref:concepts/index.adoc[Concepts]
|
||||
** xref:concepts/CharSet.adoc[CharSet]
|
||||
** xref:concepts/Rule.adoc[Rule]
|
||||
** xref:concepts/StringToken.adoc[StringToken]
|
||||
* xref:examples.adoc[Examples]
|
||||
* xref:HelpCard.adoc[Help Card]
|
||||
* xref:quicklook.adoc[]
|
||||
* xref:urls/index.adoc[]
|
||||
** xref:urls/parsing.adoc[]
|
||||
** xref:urls/containers.adoc[]
|
||||
** xref:urls/segments.adoc[]
|
||||
** xref:urls/params.adoc[]
|
||||
** xref:urls/normalization.adoc[]
|
||||
** xref:urls/stringtoken.adoc[]
|
||||
** xref:urls/percent-encoding.adoc[]
|
||||
** xref:urls/formatting.adoc[]
|
||||
* xref:grammar/index.adoc[]
|
||||
** xref:grammar/rules.adoc[]
|
||||
** xref:grammar/charset.adoc[]
|
||||
** xref:grammar/combinators.adoc[]
|
||||
** xref:grammar/range.adoc[]
|
||||
** xref:grammar/rfc3986.adoc[]
|
||||
* Concepts
|
||||
** xref:concepts/CharSet.adoc[]
|
||||
** xref:concepts/Rule.adoc[]
|
||||
** xref:concepts/StringToken.adoc[]
|
||||
* Examples
|
||||
** xref:examples/qrcode.adoc[]
|
||||
** xref:examples/finicky.adoc[]
|
||||
** xref:examples/mailto.adoc[]
|
||||
** xref:examples/magnet-link.adoc[]
|
||||
** xref:examples/file-router.adoc[]
|
||||
** xref:examples/router.adoc[]
|
||||
** xref:examples/sanitize.adoc[]
|
||||
* xref:HelpCard.adoc[]
|
||||
@@ -8,8 +8,9 @@
|
||||
//
|
||||
|
||||
|
||||
// [section:helpcard Help Card]
|
||||
[#helpcard]
|
||||
= Help Card
|
||||
|
||||
// [$url/images/HelpCard.svg]
|
||||
image:HelpCard.svg[]
|
||||
|
||||
|
||||
|
||||
@@ -16,125 +16,211 @@
|
||||
These member functions are available for interacting
|
||||
with the scheme component of URL containers:
|
||||
|
||||
// [table Scheme Members [
|
||||
// [Name]
|
||||
// [Description]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_view_base.has_scheme `has_scheme`]]
|
||||
// [
|
||||
// Return `true` if a scheme is present.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_view_base.scheme `scheme`]]
|
||||
// [
|
||||
// Return the scheme as a string.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_view_base.scheme_id `scheme_id`]]
|
||||
// [
|
||||
// Return the scheme as a
|
||||
// [link url.ref.boost__urls__scheme known scheme]
|
||||
// constant,
|
||||
// [link url.ref.boost__urls__scheme `scheme::unknown`]
|
||||
// if the scheme is not well-known, or
|
||||
// [link url.ref.boost__urls__scheme `scheme::none`]
|
||||
// if no scheme is present.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_base.remove_scheme `remove_scheme`]]
|
||||
// [
|
||||
// Remove the scheme if present.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_base.set_scheme `set_scheme`]]
|
||||
// [
|
||||
// Set the scheme to a given string or
|
||||
// [link url.ref.boost__urls__scheme known scheme]
|
||||
// constant.
|
||||
// ]
|
||||
// ]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Name|Description
|
||||
|
||||
// Row 1, Column 1
|
||||
|`has_scheme`
|
||||
// Row 1, Column 2
|
||||
|
|
||||
// Row 1, Column 3
|
||||
|Return `true` if a scheme is present.
|
||||
// Row 1, Column 4
|
||||
|
|
||||
|
||||
// Row 2, Column 1
|
||||
|`scheme`
|
||||
// Row 2, Column 2
|
||||
|
|
||||
// Row 2, Column 3
|
||||
|Return the scheme as a string.
|
||||
// Row 2, Column 4
|
||||
|
|
||||
|
||||
// Row 3, Column 1
|
||||
|`scheme_id`
|
||||
// Row 3, Column 2
|
||||
|
|
||||
// Row 3, Column 3
|
||||
|Return the scheme as a
|
||||
known scheme
|
||||
constant,
|
||||
`scheme::unknown`
|
||||
if the scheme is not well-known, or
|
||||
`scheme::none`
|
||||
if no scheme is present.
|
||||
// Row 3, Column 4
|
||||
|
|
||||
|
||||
// Row 4, Column 1
|
||||
|`remove_scheme`
|
||||
// Row 4, Column 2
|
||||
|
|
||||
// Row 4, Column 3
|
||||
|Remove the scheme if present.
|
||||
// Row 4, Column 4
|
||||
|
|
||||
|
||||
// Row 5, Column 1
|
||||
|`set_scheme`
|
||||
// Row 5, Column 2
|
||||
|
|
||||
// Row 5, Column 3
|
||||
|Set the scheme to a given string or
|
||||
known scheme
|
||||
constant.
|
||||
// Row 5, Column 4
|
||||
|
|
||||
|
||||
|===
|
||||
|
||||
|
||||
|
||||
// [table Userinfo Members [
|
||||
// [Name]
|
||||
// [Description]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_view_base.has_userinfo `has_userinfo`]]
|
||||
// [
|
||||
// Return `true` if a userinfo is present.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_view_base.encoded_userinfo `encoded_userinfo`]]
|
||||
// [
|
||||
// Return the userinfo field as a percent-encoded string.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_view_base.userinfo `userinfo`]]
|
||||
// [
|
||||
// Return the userinfo field with percent-decoding applied.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_view_base.encoded_user `encoded_user`]]
|
||||
// [
|
||||
// Return the user field as a percent-encoded string.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_view_base.user `user`]]
|
||||
// [
|
||||
// Return the user field with percent-decoding applied.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_view_base.has_password `has_password`]]
|
||||
// [
|
||||
// Return `true` if a password is present.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_view_base.encoded_password `encoded_password`]]
|
||||
// [
|
||||
// Return the password as a percent-encoded string.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_view_base.password `password`]]
|
||||
// [
|
||||
// Return the password with percent-decoding applied.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_base.set_user `set_user`]]
|
||||
// [
|
||||
// Set the user field using a plain string.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_base.remove_password `remove_password`]]
|
||||
// [
|
||||
// Remove the password field if present.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_base.set_encoded_password `set_encoded_password`]]
|
||||
// [
|
||||
// Set the password field using a percent-encoded string.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_base.set_password `set_password`]]
|
||||
// [
|
||||
// Set the password field using a plain string.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_base.remove_userinfo `remove_userinfo`]]
|
||||
// [
|
||||
// Remove the entire userinfo if present.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_base.set_encoded_userinfo `set_encoded_userinfo`]]
|
||||
// [
|
||||
// Set the entire userinfo using a percent-encoded string.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__url_base.set_userinfo `set_userinfo`]]
|
||||
// [
|
||||
// Set the entire userinfo using a plain string.
|
||||
// ]
|
||||
// ]]
|
||||
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Name|Description
|
||||
|
||||
// Row 1, Column 1
|
||||
|`has_userinfo`
|
||||
// Row 1, Column 2
|
||||
|
|
||||
// Row 1, Column 3
|
||||
|Return `true` if a userinfo is present.
|
||||
// Row 1, Column 4
|
||||
|
|
||||
|
||||
// Row 2, Column 1
|
||||
|`encoded_userinfo`
|
||||
// Row 2, Column 2
|
||||
|
|
||||
// Row 2, Column 3
|
||||
|Return the userinfo field as a percent-encoded string.
|
||||
// Row 2, Column 4
|
||||
|
|
||||
|
||||
// Row 3, Column 1
|
||||
|`userinfo`
|
||||
// Row 3, Column 2
|
||||
|
|
||||
// Row 3, Column 3
|
||||
|Return the userinfo field with percent-decoding applied.
|
||||
// Row 3, Column 4
|
||||
|
|
||||
|
||||
// Row 4, Column 1
|
||||
|`encoded_user`
|
||||
// Row 4, Column 2
|
||||
|
|
||||
// Row 4, Column 3
|
||||
|Return the user field as a percent-encoded string.
|
||||
// Row 4, Column 4
|
||||
|
|
||||
|
||||
// Row 5, Column 1
|
||||
|`user`
|
||||
// Row 5, Column 2
|
||||
|
|
||||
// Row 5, Column 3
|
||||
|Return the user field with percent-decoding applied.
|
||||
// Row 5, Column 4
|
||||
|
|
||||
|
||||
// Row 6, Column 1
|
||||
|`has_password`
|
||||
// Row 6, Column 2
|
||||
|
|
||||
// Row 6, Column 3
|
||||
|Return `true` if a password is present.
|
||||
// Row 6, Column 4
|
||||
|
|
||||
|
||||
// Row 7, Column 1
|
||||
|`encoded_password`
|
||||
// Row 7, Column 2
|
||||
|
|
||||
// Row 7, Column 3
|
||||
|Return the password as a percent-encoded string.
|
||||
// Row 7, Column 4
|
||||
|
|
||||
|
||||
// Row 8, Column 1
|
||||
|`password`
|
||||
// Row 8, Column 2
|
||||
|
|
||||
// Row 8, Column 3
|
||||
|Return the password with percent-decoding applied.
|
||||
// Row 8, Column 4
|
||||
|
|
||||
|
||||
// Row 9, Column 1
|
||||
|`set_user`
|
||||
// Row 9, Column 2
|
||||
|
|
||||
// Row 9, Column 3
|
||||
|Set the user field using a plain string.
|
||||
// Row 9, Column 4
|
||||
|
|
||||
|
||||
// Row 10, Column 1
|
||||
|`remove_password`
|
||||
// Row 10, Column 2
|
||||
|
|
||||
// Row 10, Column 3
|
||||
|Remove the password field if present.
|
||||
// Row 10, Column 4
|
||||
|
|
||||
|
||||
// Row 11, Column 1
|
||||
|`set_encoded_password`
|
||||
// Row 11, Column 2
|
||||
|
|
||||
// Row 11, Column 3
|
||||
|Set the password field using a percent-encoded string.
|
||||
// Row 11, Column 4
|
||||
|
|
||||
|
||||
// Row 12, Column 1
|
||||
|`set_password`
|
||||
// Row 12, Column 2
|
||||
|
|
||||
// Row 12, Column 3
|
||||
|Set the password field using a plain string.
|
||||
// Row 12, Column 4
|
||||
|
|
||||
|
||||
// Row 13, Column 1
|
||||
|`remove_userinfo`
|
||||
// Row 13, Column 2
|
||||
|
|
||||
// Row 13, Column 3
|
||||
|Remove the entire userinfo if present.
|
||||
// Row 13, Column 4
|
||||
|
|
||||
|
||||
// Row 14, Column 1
|
||||
|`set_encoded_userinfo`
|
||||
// Row 14, Column 2
|
||||
|
|
||||
// Row 14, Column 3
|
||||
|Set the entire userinfo using a percent-encoded string.
|
||||
// Row 14, Column 4
|
||||
|
|
||||
|
||||
// Row 15, Column 1
|
||||
|`set_userinfo`
|
||||
// Row 15, Column 2
|
||||
|
|
||||
// Row 15, Column 3
|
||||
|Set the entire userinfo using a plain string.
|
||||
// Row 15, Column 4
|
||||
|
|
||||
|
||||
|===
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,19 +8,17 @@
|
||||
//
|
||||
|
||||
|
||||
// [section:charset CharSet]
|
||||
[#charset]
|
||||
= CharSet
|
||||
|
||||
A __CharSet__ is a unary predicate which is invocable with
|
||||
this equivalent signature:
|
||||
A __CharSet__ is a unary predicate which is invocable with this equivalent signature:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
bool( char ch ) const noexcept;
|
||||
----
|
||||
|
||||
|
||||
The predicate returns `true` if `ch` is a member of the
|
||||
set, or `false` otherwise.
|
||||
The predicate returns `true` if `ch` is a member of the set, or `false` otherwise.
|
||||
|
||||
== Related Identifiers
|
||||
|
||||
@@ -37,74 +35,90 @@ In this table:
|
||||
* `c` is a value of type `char`
|
||||
* `first`, `last` are values of type `char const*`
|
||||
|
||||
// [table Valid expressions
|
||||
// [[Expression] [Type] [Semantics, Pre/Post-conditions]]
|
||||
// [
|
||||
// [`t(c)`]
|
||||
// [`bool`]
|
||||
// [
|
||||
// This function returns `true` if `c` is a member of
|
||||
// the character set, otherwise it returns `false`.
|
||||
// ]
|
||||
// ][
|
||||
// [
|
||||
// ```
|
||||
// t.find_if(first,last)
|
||||
// ```
|
||||
// ]
|
||||
// [`char const*`]
|
||||
// [
|
||||
// This optional member function examines the valid
|
||||
// range of characters in `[first, last)` and returns
|
||||
// a pointer to the first occurrence of a character
|
||||
// which is in the set, or returns `last` if no such
|
||||
// character.
|
||||
//
|
||||
// The implementation of
|
||||
// [link url.ref.boost__urls__grammar__find_if `find_if`]
|
||||
// calls this function if provided by the character
|
||||
// set, allowing optimized or otherwise performant
|
||||
// implementations to be developed. If this member
|
||||
// function is not provided, a default implementation
|
||||
// is used which calls `operator()`.
|
||||
// ]
|
||||
// ][
|
||||
// [
|
||||
// ```
|
||||
// t.find_if_not(first,last)
|
||||
// ```
|
||||
// ]
|
||||
// [`char const*`]
|
||||
// [
|
||||
// This optional member function examines the valid
|
||||
// range of characters in `[first, last)` and returns
|
||||
// a pointer to the first occurrence of a character
|
||||
// which is not in the set, or returns `last` if no
|
||||
// such character.
|
||||
//
|
||||
// The implementation of
|
||||
// [link url.ref.boost__urls__grammar__find_if_not `find_if_not`]
|
||||
// calls this function if provided by the character
|
||||
// set, allowing optimized or otherwise performant
|
||||
// implementations to be developed. If this member
|
||||
// function is not provided, a default implementation
|
||||
// is used which calls `operator()`.
|
||||
// ]
|
||||
// ]]
|
||||
//
|
||||
// [heading Exemplar]
|
||||
//
|
||||
// For best results, it is suggested that all constructors and
|
||||
// member functions for character sets be marked `constexpr`.
|
||||
//
|
||||
// [code_charset_1]
|
||||
//
|
||||
// [heading Models]
|
||||
//
|
||||
// * [link url.ref.boost__urls__grammar__alnum_chars `alnum_chars`]
|
||||
// * [link url.ref.boost__urls__grammar__alpha_chars `alpha_chars`]
|
||||
// * [link url.ref.boost__urls__grammar__digit_chars `digit_chars`]
|
||||
// * [link url.ref.boost__urls__grammar__hexdig_chars `hexdig_chars`]
|
||||
// * [link url.ref.boost__urls__grammar__lut_chars `lut_chars`]
|
||||
//
|
||||
// [endsect]
|
||||
[cols="a,a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Expression|Type|Semantics, Pre/Post-conditions
|
||||
|
||||
// Row 1, Column 1
|
||||
|`t(c)`
|
||||
// Row 1, Column 2
|
||||
|`bool`
|
||||
// Row 1, Column 3
|
||||
|This function returns `true` if `c` is a member of
|
||||
the character set, otherwise it returns `false`.
|
||||
|
||||
// Row 2, Column 1
|
||||
|
|
||||
[source,cpp]
|
||||
----
|
||||
t.find_if(first,last)
|
||||
----
|
||||
|
||||
// Row 2, Column 2
|
||||
|`char const*`
|
||||
// Row 2, Column 3
|
||||
|This optional member function examines the valid range of characters in `// [first, last)` and returns
|
||||
a pointer to the first occurrence of a character
|
||||
which is in the set, or returns `last` if no such
|
||||
character.
|
||||
|
||||
The implementation of `grammar::find_if`
|
||||
calls this function if provided by the character
|
||||
set, allowing optimized or otherwise performant
|
||||
implementations to be developed. If this member
|
||||
function is not provided, a default implementation
|
||||
is used which calls `operator()`.
|
||||
|
||||
// Row 3, Column 1
|
||||
|
|
||||
[source,cpp]
|
||||
----
|
||||
t.find_if_not(first,last)
|
||||
----
|
||||
// Row 3, Column 2
|
||||
|`char const*`
|
||||
// Row 3, Column 3
|
||||
|This optional member function examines the valid
|
||||
range of characters in `[first, last)` and returns
|
||||
a pointer to the first occurrence of a character
|
||||
which is not in the set, or returns `last` if no
|
||||
such character.
|
||||
|
||||
The implementation of `grammar::find_if_not`
|
||||
calls this function if provided by the character
|
||||
set, allowing optimized or otherwise performant
|
||||
implementations to be developed. If this member
|
||||
function is not provided, a default implementation
|
||||
is used which calls `operator()`.
|
||||
|===
|
||||
|
||||
== Exemplar
|
||||
|
||||
For best results, it is suggested that all constructors and
|
||||
member functions for character sets be marked `constexpr`.
|
||||
|
||||
// code_charset_1
|
||||
[source,cpp]
|
||||
----
|
||||
struct CharSet
|
||||
{
|
||||
bool operator()( char c ) const noexcept;
|
||||
|
||||
// These are both optional. If either or both are left
|
||||
// unspecified, a default implementation will be used.
|
||||
//
|
||||
char const* find_if( char const* first, char const* last ) const noexcept;
|
||||
char const* find_if_not( char const* first, char const* last ) const noexcept;
|
||||
};
|
||||
----
|
||||
|
||||
== Models
|
||||
|
||||
* `grammar::alnum_chars`
|
||||
* `grammar::alpha_chars`
|
||||
* `grammar::digit_chars`
|
||||
* `grammar::hexdig_chars`
|
||||
* `grammar::lut_chars`
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//
|
||||
|
||||
|
||||
== Rule
|
||||
= Rule
|
||||
|
||||
A __Rule__ defines an algorithm used to match an input buffer of
|
||||
ASCII characters against a set of syntactical specifications.
|
||||
@@ -18,11 +18,11 @@ rules for productions typically found in RFC documents. Rules
|
||||
are not invoked directly; instead, rule variables are used with
|
||||
overloads of `parse` which provide a convenient, uniform front end.
|
||||
|
||||
=== Related Identifiers
|
||||
== Related Identifiers
|
||||
|
||||
`is_rule`, `parse`.
|
||||
|
||||
=== Requirements
|
||||
== Requirements
|
||||
|
||||
In this table:
|
||||
|
||||
@@ -31,79 +31,84 @@ In this table:
|
||||
* `it` is an __lvalue__ with type `char const*`
|
||||
* `end` is a value of type `char const*`
|
||||
|
||||
// [table Valid expressions
|
||||
// [[Expression] [Type] [Semantics, Pre/Post-conditions]]
|
||||
// [
|
||||
// [
|
||||
// ```
|
||||
// T(t)
|
||||
// ```
|
||||
// ]
|
||||
// []
|
||||
// [
|
||||
// Copy construction of `T` throws nothing.
|
||||
//
|
||||
// `std::is_nothrow_copy_constructible<T>::value == true`
|
||||
// ]
|
||||
// ][
|
||||
// [
|
||||
// ```
|
||||
// T::value_type
|
||||
// ```
|
||||
// ]
|
||||
// []
|
||||
// [
|
||||
// Values of this type are returned by the rule when the
|
||||
// parse operation is successful
|
||||
// ]
|
||||
// ][
|
||||
// [
|
||||
// ```
|
||||
// t.parse(it,end)
|
||||
// ```
|
||||
// ]
|
||||
// [`result<T::value_type>`]
|
||||
// [
|
||||
// Attempt to parse the buffer of characters defined by
|
||||
// the range `[it,end)`. Upon success, the return result
|
||||
// holds an instance of the rule's value type, and
|
||||
// the reference parameter `it` is modified to point
|
||||
// to the first unconsumed character. Otherwise, upon
|
||||
// failure the result holds an error. In this case
|
||||
// the implementation defines if and how the reference
|
||||
// parameter `it` is modified.
|
||||
// ]
|
||||
// ]]
|
||||
//
|
||||
// [heading Exemplar]
|
||||
//
|
||||
// For best results, it is suggested that all constructors for
|
||||
// rules be marked `constexpr`.
|
||||
//
|
||||
// ```
|
||||
// struct Rule
|
||||
// {
|
||||
// struct value_type;
|
||||
//
|
||||
// constexpr Rule( Rule const& ) noexcept = default;
|
||||
//
|
||||
// auto parse( char const*& it, char const* end ) const -> result< value_type >;
|
||||
// };
|
||||
//
|
||||
// // Declare a variable of type Rule for notational convenience
|
||||
// constexpr Rule rule{};
|
||||
// ```
|
||||
//
|
||||
// [heading Models]
|
||||
//
|
||||
// * __dec_octet_rule__
|
||||
// * __delim_rule__
|
||||
// * __not_empty_rule__
|
||||
// * __optional_rule__
|
||||
// * __range_rule__
|
||||
// * __token_rule__
|
||||
// * __tuple_rule__
|
||||
// * __unsigned_rule__
|
||||
// * __variant_rule__
|
||||
//
|
||||
// [endsect]
|
||||
[cols="a,a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Expression|Type|Semantics, Pre/Post-conditions
|
||||
|
||||
// Row 1, Column 1
|
||||
|[source,cpp]
|
||||
----
|
||||
T(t)
|
||||
----
|
||||
|
||||
// Row 1, Column 2
|
||||
| -
|
||||
// Row 1, Column 3
|
||||
|Copy construction of `T` throws nothing.
|
||||
|
||||
`std::is_nothrow_copy_constructible<T>::value == true`
|
||||
|
||||
// Row 2, Column 1
|
||||
|[source,cpp]
|
||||
----
|
||||
T::value_type
|
||||
----
|
||||
|
||||
// Row 2, Column 2
|
||||
| -
|
||||
// Row 2, Column 3
|
||||
|Values of this type are returned by the rule when the
|
||||
parse operation is successful
|
||||
|
||||
// Row 3, Column 1
|
||||
|[source,cpp]
|
||||
----
|
||||
t.parse(it,end)
|
||||
----
|
||||
|
||||
// Row 3, Column 2
|
||||
|`result<T::value_type>`
|
||||
// Row 3, Column 3
|
||||
|Attempt to parse the buffer of characters defined by
|
||||
the range `// [it,end)`. Upon success, the return result
|
||||
holds an instance of the rule's value type, and
|
||||
the reference parameter `it` is modified to point
|
||||
to the first unconsumed character. Otherwise, upon
|
||||
failure the result holds an error. In this case
|
||||
the implementation defines if and how the reference
|
||||
parameter `it` is modified.
|
||||
|
||||
|===
|
||||
|
||||
== Exemplar
|
||||
|
||||
For best results, it is suggested that all constructors for
|
||||
rules be marked `constexpr`.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
struct Rule
|
||||
{
|
||||
struct value_type;
|
||||
|
||||
constexpr Rule( Rule const& ) noexcept = default;
|
||||
|
||||
auto parse( char const*& it, char const* end ) const -> result< value_type >;
|
||||
};
|
||||
|
||||
// Declare a variable of type Rule for notational convenience
|
||||
constexpr Rule rule{};
|
||||
----
|
||||
|
||||
== Model
|
||||
|
||||
* `grammar::dec_octet_rule`
|
||||
* `grammar::delim_rule`
|
||||
* `grammar::not_empty_rule`
|
||||
* `grammar::optional_rule`
|
||||
* `grammar::range_rule`
|
||||
* `grammar::token_rule`
|
||||
* `grammar::tuple_rule`
|
||||
* `grammar::unsigned_rule`
|
||||
* `grammar::variant_rule`
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//
|
||||
|
||||
|
||||
== StringToken
|
||||
= StringToken
|
||||
|
||||
A string token is an rvalue passed to a function template which
|
||||
customizes the return type of the function and also controls how
|
||||
@@ -18,7 +18,7 @@ function call in which it appears as a parameter. A string
|
||||
token cannot be copied, moved, or assigned, and must be
|
||||
destroyed when the function returns or throws.
|
||||
|
||||
=== Requirements
|
||||
== Requirements
|
||||
|
||||
In this table:
|
||||
|
||||
@@ -26,73 +26,81 @@ In this table:
|
||||
* `t` is an rvalue reference of type T
|
||||
* `n` is a value of type `std::size_t`
|
||||
|
||||
// [table Valid expressions
|
||||
// [[Expression] [Result] [Semantics, Pre/Post-conditions]]
|
||||
// [
|
||||
// [
|
||||
// ```
|
||||
// std::derived_from<T,string_token::arg>
|
||||
// ```
|
||||
// ]
|
||||
// [
|
||||
// ```
|
||||
// true
|
||||
// ```
|
||||
// ]
|
||||
// [
|
||||
// All string tokens must be publicly and
|
||||
// unambiguously derived from
|
||||
// [link url.ref.boost__urls__string_token__arg `string_token::arg`].
|
||||
// ]
|
||||
// ][
|
||||
// [
|
||||
// ```
|
||||
// T::result_type
|
||||
// ```
|
||||
// ]
|
||||
// []
|
||||
// [
|
||||
// This type determines the return type of functions
|
||||
// which accept a string token.
|
||||
// ]
|
||||
// ][
|
||||
// [
|
||||
// ```
|
||||
// t.prepare(n);
|
||||
// ```
|
||||
// ]
|
||||
// [
|
||||
// ```
|
||||
// char*
|
||||
// ```
|
||||
// ]
|
||||
// [
|
||||
// This function overrides the virtual function in the base.
|
||||
// It must return a pointer to a character buffer of at least
|
||||
// size `n`, otherwise throw an exception.
|
||||
// ]
|
||||
// ][
|
||||
// [
|
||||
// ```
|
||||
// t.result();
|
||||
// ```
|
||||
// ]
|
||||
// [
|
||||
// ```
|
||||
// T::result_type
|
||||
// ```
|
||||
// ]
|
||||
// [
|
||||
// This function is invoked by the algorithm to receive the result
|
||||
// from the string token.
|
||||
// It is only invoked if `prepare` returned successfuly and the
|
||||
// string token was not destroyed.
|
||||
// ]
|
||||
// ]]
|
||||
[cols="a,a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Expression|Result|Semantics, Pre/Post-conditions
|
||||
|
||||
// Row 1, Column 1
|
||||
|[source,cpp]
|
||||
----
|
||||
std::derived_from<T,string_token::arg>
|
||||
----
|
||||
|
||||
// Row 1, Column 2
|
||||
|[source,cpp]
|
||||
----
|
||||
true
|
||||
----
|
||||
|
||||
// Row 1, Column 3
|
||||
|All string tokens must be publicly and
|
||||
unambiguously derived from
|
||||
`string_token::arg`.
|
||||
|
||||
// Row 2, Column 1
|
||||
|[source,cpp]
|
||||
----
|
||||
T::result_type
|
||||
----
|
||||
|
||||
// Row 2, Column 2
|
||||
|
|
||||
// Row 2, Column 3
|
||||
|This type determines the return type of functions
|
||||
which accept a string token.
|
||||
|
||||
// Row 3, Column 1
|
||||
|[source,cpp]
|
||||
----
|
||||
t.prepare(n);
|
||||
----
|
||||
|
||||
// Row 3, Column 2
|
||||
|[source,cpp]
|
||||
----
|
||||
char*
|
||||
----
|
||||
|
||||
// Row 3, Column 3
|
||||
|This function overrides the virtual function in the base.
|
||||
It must return a pointer to a character buffer of at least
|
||||
size `n`, otherwise throw an exception.
|
||||
|
||||
// Row 4, Column 1
|
||||
|[source,cpp]
|
||||
----
|
||||
t.result();
|
||||
----
|
||||
|
||||
// Row 4, Column 3
|
||||
|[source,cpp]
|
||||
----
|
||||
T::result_type
|
||||
----
|
||||
|
||||
// Row 4, Column 5
|
||||
|This function is invoked by the algorithm to receive the result
|
||||
from the string token.
|
||||
It is only invoked if `prepare` returned successfuly and the
|
||||
string token was not destroyed.
|
||||
|
||||
|===
|
||||
|
||||
|
||||
|
||||
=== Algorithm Requirements
|
||||
|
||||
== Algorithm Requirements
|
||||
|
||||
When an algorithm accepts a string token, it must meet these requirements:
|
||||
|
||||
@@ -105,7 +113,7 @@ String tokens cannot be reused.
|
||||
|
||||
|
||||
|
||||
=== Exemplars
|
||||
== Exemplars
|
||||
|
||||
String token prototype:
|
||||
|
||||
@@ -166,9 +174,9 @@ algorithm( StringToken&& token = {} ) ->
|
||||
|
||||
Models
|
||||
|
||||
* `append_to`
|
||||
* `assign_to`
|
||||
* `preserve_size`
|
||||
* `append_to`
|
||||
* `string_token::return_string`
|
||||
* `string_token::assign_to`
|
||||
* `string_token::preserve_size`
|
||||
* `string_token::return_string`
|
||||
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
//
|
||||
|
||||
|
||||
== Concepts
|
||||
= Concepts
|
||||
|
||||
This section describes all of the concepts defined by the library.
|
||||
|
||||
// [include 5.1.CharSet.qbk]
|
||||
// [include 5.2.Rule.qbk]
|
||||
// [include 5.3.StringToken.qbk]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/url
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
== Examples
|
||||
|
||||
=== QR Code
|
||||
|
||||
A QR code is a machine-readable two-dimensional barcode. They might contain data
|
||||
for a identifier or a URL to a website.
|
||||
|
||||
This example shows how to construct and modify URLs to consume a third party API to
|
||||
generate QR Codes.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// example_qrcode
|
||||
----
|
||||
|
||||
|
||||
|
||||
=== Finicky
|
||||
|
||||
This example shows how to classify URLs according to a set of rules. It is
|
||||
inspired by https://github.com/johnste/finicky[Finicky,window=blank_] application.
|
||||
|
||||
The URLs are classified and redirected to a browser according to their
|
||||
category. See the example `config.json` file.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// example_finicky
|
||||
----
|
||||
|
||||
|
||||
|
||||
=== mailto URLs
|
||||
|
||||
`mailto` is a URL scheme for email addresses. `mailto` URL are used on websites
|
||||
to allow users to send an email to a specific address directly from an HTML document.
|
||||
|
||||
This example parses a mailto URL into a new view type and prints its components to
|
||||
standard output.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// example_mailto
|
||||
----
|
||||
|
||||
|
||||
|
||||
=== Magnet Link
|
||||
|
||||
`magnet` is a URL scheme for identifying files by their content. These files are
|
||||
usually identified by cryptographic hash value.
|
||||
|
||||
Magnet links are useful in peer-to-peer file sharing networks because they allow
|
||||
resources to be referred to without the need for a continuously available host..
|
||||
|
||||
This example parses a magnet link into a new view type and prints its components to
|
||||
standard output.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// example_magnet
|
||||
----
|
||||
|
||||
|
||||
|
||||
=== File Router
|
||||
|
||||
This example defines a router that associates URL paths to a directory in the filesystem. If
|
||||
the specified route matches and the file exists, the example prints its contents to standard output.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// example_file_router
|
||||
----
|
||||
|
||||
|
||||
|
||||
=== Router
|
||||
|
||||
This example defines a router for URL paths. If the specified route matches one of the existing
|
||||
routes, the example executes the underlying callback function.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// example_router
|
||||
----
|
||||
|
||||
|
||||
|
||||
=== Sanitizing URLs
|
||||
|
||||
This example parses a non-strict or invalid URL
|
||||
into path components according to its delimiters.
|
||||
This pattern can be adapted to the requirements of other
|
||||
applications.
|
||||
|
||||
Once the non-strict components are determined, a new URL is
|
||||
created and its parts are set with the `set_encoded_X`
|
||||
functions, which will encode any invalid chars accordingly.
|
||||
|
||||
This sort of transformation is useful in applications that are
|
||||
extremely loose in what kinds of URLs they accept, such as
|
||||
browsers. The sanitized URL can later be used for machine-to-machine
|
||||
communication.
|
||||
|
||||
Using non-strict URLs directly is a security concern in
|
||||
machine-to-machine communication, is ambiguous, and also
|
||||
involve an extra cost for the transformations.
|
||||
|
||||
Different transformations are required by different applications to
|
||||
construct a valid URL appropriate for machine-to-machine communication.
|
||||
For instance, if an invalid relative reference includes something that
|
||||
looks like a host in the first path segment, browsers usually interpret
|
||||
that as the host with an implicit "https" scheme. Other applications
|
||||
also have other implicit schemes.
|
||||
|
||||
The example also identifies whether the input url is already valid.
|
||||
It includes diagnostics that can be used to help the user determine
|
||||
if a URL is invalid and why it's invalid.
|
||||
|
||||
Once all transformations are applied, the result is a URL
|
||||
appropriate for machine-to-machine communication.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// example_sanitize_url
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
221
doc/modules/ROOT/pages/examples/file-router.adoc
Normal file
221
doc/modules/ROOT/pages/examples/file-router.adoc
Normal file
@@ -0,0 +1,221 @@
|
||||
//
|
||||
// Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/url
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
= File Router
|
||||
|
||||
This example defines a router that associates URL paths to a directory in the filesystem. If
|
||||
the specified route matches and the file exists, the example prints its contents to standard output.
|
||||
|
||||
// example_file_router
|
||||
[source,cpp]
|
||||
----
|
||||
|
||||
/*
|
||||
This example defines a route for a URL path.
|
||||
If the specified route matches and the file
|
||||
exists, the example prints its contents to
|
||||
standard output.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <boost/url/error.hpp>
|
||||
#include <boost/url/parse.hpp>
|
||||
#include <boost/url/segments_encoded_ref.hpp>
|
||||
#include <boost/url/segments_encoded_view.hpp>
|
||||
#include <boost/url/string_view.hpp>
|
||||
#include <boost/url/url.hpp>
|
||||
#include <boost/url/url_view.hpp>
|
||||
#include <boost/url/static_url.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace urls = boost::urls;
|
||||
namespace fs = boost::filesystem;
|
||||
namespace core = boost::core;
|
||||
using string_view = boost::core::string_view;
|
||||
|
||||
/** Check if a target matches a prefix
|
||||
|
||||
This function checks if the first segments
|
||||
of the target match the corresponding prefix
|
||||
segments.
|
||||
|
||||
@param target Target segments
|
||||
@param prefix Prefix segments
|
||||
@return True if target matches prefix
|
||||
*/
|
||||
bool match_prefix(
|
||||
urls::segments_view target,
|
||||
urls::segments_view prefix)
|
||||
{
|
||||
// Trivially reject target that cannot
|
||||
// contain the prefix
|
||||
if (target.size() < prefix.size())
|
||||
return false;
|
||||
|
||||
// Match the prefix segments
|
||||
auto it0 = target.begin();
|
||||
auto end0 = target.end();
|
||||
auto it1 = prefix.begin();
|
||||
auto end1 = prefix.end();
|
||||
while (
|
||||
it0 != end0 &&
|
||||
it1 != end1 &&
|
||||
*it0 == *it1)
|
||||
{
|
||||
++it0;
|
||||
++it1;
|
||||
}
|
||||
return it1 == end1;
|
||||
}
|
||||
|
||||
/** A static route representing files in a directory
|
||||
|
||||
A route is a URL logical prefix representing
|
||||
static files in the specified root directory.
|
||||
|
||||
The `match` function returns the corresponding
|
||||
file for a given URL path.
|
||||
*/
|
||||
class route
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
route(core::string_view prefix, fs::path root)
|
||||
: prefix_(urls::parse_uri_reference(prefix).value())
|
||||
, root_(std::move(root))
|
||||
{}
|
||||
|
||||
/// Constructor
|
||||
route(urls::url prefix, fs::path root)
|
||||
: prefix_(std::move(prefix))
|
||||
, root_(std::move(root))
|
||||
{}
|
||||
|
||||
/** Match target URL path with a file
|
||||
|
||||
This function attempts to match the target
|
||||
URL path with the route prefix.
|
||||
|
||||
If the prefix matches, the target is
|
||||
considered to represent a file in the root
|
||||
directory. When that happens, the target
|
||||
prefix is consumed and other segments are
|
||||
appended to the root path.
|
||||
|
||||
The complete file path represented by the
|
||||
target is returned as the output parameter
|
||||
`result`.
|
||||
|
||||
@param target Target URL path
|
||||
@param result An out-parameter holding the resulting path
|
||||
@return `true` if target matches the directory
|
||||
*/
|
||||
bool match(
|
||||
urls::url_view target,
|
||||
fs::path& result)
|
||||
{
|
||||
if (match_prefix(
|
||||
target.segments(),
|
||||
static_cast<urls::url_view>(prefix_).segments()))
|
||||
{
|
||||
result = root_;
|
||||
auto segs = target.segments();
|
||||
auto it = segs.begin();
|
||||
auto end = segs.end();
|
||||
std::advance(it, prefix_.segments().size());
|
||||
while (it != end)
|
||||
{
|
||||
auto seg = *it;
|
||||
result.append(seg.begin(), seg.end());
|
||||
++it;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
urls::url prefix_;
|
||||
fs::path root_;
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
namespace urls = boost::urls;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
// Check command line arguments.
|
||||
if (argc != 4)
|
||||
{
|
||||
fs::path exec = argv[0];
|
||||
exec = exec.filename();
|
||||
std::cerr
|
||||
<< "Usage: " << exec
|
||||
<< " <target> <prefix> <doc_root>\n"
|
||||
"target: path to make a request\n"
|
||||
"prefix: url prefix\n"
|
||||
"doc_root: dir to look for files\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
urls::url target =
|
||||
urls::parse_uri_reference(argv[1]).value();
|
||||
target.normalize_path();
|
||||
|
||||
std::string prefix = argv[2];
|
||||
fs::path root = argv[2];
|
||||
|
||||
if (!fs::is_directory(root))
|
||||
{
|
||||
std::cerr
|
||||
<< "Error: " << root
|
||||
<< " is not a directory\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Create route
|
||||
route r(prefix, root);
|
||||
|
||||
// Check if target matches a file
|
||||
fs::path result;
|
||||
if (r.match(target, result))
|
||||
{
|
||||
fs::ifstream f(result);
|
||||
std::string l;
|
||||
while (std::getline(f, l))
|
||||
std::cout << l << '\n';
|
||||
f.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout
|
||||
<< "No " << target << " in prefix "
|
||||
<< prefix << std::endl;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
std::cerr << e.what() << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
|
||||
413
doc/modules/ROOT/pages/examples/finicky.adoc
Normal file
413
doc/modules/ROOT/pages/examples/finicky.adoc
Normal file
@@ -0,0 +1,413 @@
|
||||
//
|
||||
// Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/url
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
= Finicky
|
||||
|
||||
This example shows how to classify URLs according to a set of rules. It is
|
||||
inspired by https://github.com/johnste/finicky[Finicky,window=blank_] application.
|
||||
|
||||
The URLs are classified and redirected to a browser according to their
|
||||
category. See the example `config.json` file.
|
||||
|
||||
// example_finicky
|
||||
[source,cpp]
|
||||
----
|
||||
|
||||
/*
|
||||
This example shows how to classify URLs
|
||||
according to a set of rules. This example is
|
||||
inspired by Finicky. The URLs are classified
|
||||
and redirected to a browser according to their
|
||||
category. See the example config.json file.
|
||||
https://github.com/johnste/finicky
|
||||
*/
|
||||
|
||||
#include <boost/url/url.hpp>
|
||||
#include <boost/url/parse.hpp>
|
||||
#include <boost/system/result.hpp>
|
||||
#include <boost/json/stream_parser.hpp>
|
||||
#include <boost/core/detail/string_view.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
namespace urls = boost::urls;
|
||||
namespace json = boost::json;
|
||||
namespace core = boost::core;
|
||||
|
||||
json::value
|
||||
read_json( std::istream& is, json::error_code& ec )
|
||||
{
|
||||
json::parse_options opt;
|
||||
opt.allow_comments = true;
|
||||
json::stream_parser p(json::storage_ptr(), opt);
|
||||
std::string line;
|
||||
while( std::getline( is, line ) )
|
||||
{
|
||||
p.write( line, ec );
|
||||
if( ec )
|
||||
return nullptr;
|
||||
}
|
||||
p.finish( ec );
|
||||
if( ec )
|
||||
return nullptr;
|
||||
return p.release();
|
||||
}
|
||||
|
||||
bool
|
||||
glob_match(
|
||||
core::string_view pattern,
|
||||
core::string_view str)
|
||||
{
|
||||
// regex
|
||||
if (str.starts_with("/") &&
|
||||
str.ends_with("/"))
|
||||
{
|
||||
const boost::regex pr(pattern.begin() + 1, pattern.end() - 1);
|
||||
return boost::regex_match(std::string(str), pr);
|
||||
}
|
||||
|
||||
// literal
|
||||
if (!pattern.contains('*'))
|
||||
{
|
||||
return pattern == str;
|
||||
}
|
||||
|
||||
// glob
|
||||
std::string p = pattern;
|
||||
std::size_t i = p.find('*');
|
||||
while (i != std::string::npos)
|
||||
{
|
||||
auto e = std::min(p.find_first_not_of('*', i), p.size());
|
||||
std::size_t n = e - i;
|
||||
if (n == 1)
|
||||
{
|
||||
p.replace(i, e, "[^/]*");
|
||||
i += 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
p.replace(i, e, ".*");
|
||||
i += 2;
|
||||
}
|
||||
i = p.find('*', i);
|
||||
}
|
||||
const boost::regex pr(p);
|
||||
return boost::regex_match(std::string(str), pr);
|
||||
}
|
||||
|
||||
bool
|
||||
url_match(
|
||||
json::value& mv,
|
||||
urls::url const& u)
|
||||
{
|
||||
if (mv.is_string())
|
||||
{
|
||||
json::string& p = mv.as_string();
|
||||
return glob_match(u.buffer(), p);
|
||||
}
|
||||
else if (mv.is_array())
|
||||
{
|
||||
json::array& m = mv.as_array();
|
||||
for (auto& mi: m)
|
||||
{
|
||||
if (!mi.is_string())
|
||||
throw std::invalid_argument(
|
||||
"handle match is not a string");
|
||||
if (glob_match(mi.as_string(), u.buffer()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (mv.is_object())
|
||||
{
|
||||
json::object& m = mv.as_object();
|
||||
std::pair<core::string_view, core::string_view>
|
||||
field_values[] = {
|
||||
{"protocol", u.scheme()},
|
||||
{"authority", u.encoded_authority()},
|
||||
{"username", u.encoded_user()},
|
||||
{"user", u.encoded_user()},
|
||||
{"password", u.encoded_password()},
|
||||
{"userinfo", u.encoded_userinfo()},
|
||||
{"host", u.encoded_host()},
|
||||
{"port", u.port()},
|
||||
{"path", u.encoded_path()},
|
||||
{"pathname", u.encoded_path()},
|
||||
{"query", u.encoded_query()},
|
||||
{"search", u.encoded_query()},
|
||||
{"fragment", u.encoded_fragment()},
|
||||
{"hash", u.encoded_fragment()},
|
||||
};
|
||||
for (auto& p: field_values)
|
||||
{
|
||||
auto it = m.find(p.first);
|
||||
if (it != m.end())
|
||||
{
|
||||
if (!it->value().is_string())
|
||||
throw std::invalid_argument(
|
||||
"match fields should be a strings");
|
||||
if (glob_match(p.second, p.first))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define CHECK(c, msg) \
|
||||
if (!(c)) \
|
||||
{ \
|
||||
std::cerr << msg << "\n"; \
|
||||
return EXIT_FAILURE; \
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
std::cout << argv[0] << "\n";
|
||||
std::cout << "Usage: finicky <config> <url>\n"
|
||||
"options:\n"
|
||||
" <config>: Configuration file\n"
|
||||
" <url>: The url to open\n"
|
||||
"examples:\n"
|
||||
" finicky config.json \"http://www.example.com\"\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Parse url
|
||||
boost::system::result<urls::url> ru = urls::parse_uri(argv[2]);
|
||||
CHECK(ru, "Invalid URL");
|
||||
urls::url u = *ru;
|
||||
|
||||
// Open config file
|
||||
std::fstream fin(argv[1]);
|
||||
CHECK(fin.good(), "Cannot open configuration file");
|
||||
json::error_code ec;
|
||||
json::value c = read_json(fin, ec);
|
||||
CHECK(!ec.failed(), "Cannot parse configuration file");
|
||||
CHECK(c.is_object(), "Configuration file is not an object");
|
||||
json::object& o = c.as_object();
|
||||
|
||||
// Set initial browser
|
||||
auto bit = o.find("defaultBrowser");
|
||||
CHECK(
|
||||
bit != o.end(),
|
||||
"Configuration file has no defaultBrowser");
|
||||
CHECK(
|
||||
bit->value().is_string(),
|
||||
"defaultBrowser should be a string");
|
||||
json::string& browser = bit->value().as_string();
|
||||
|
||||
// Apply rewrites to the input string
|
||||
auto rsit = o.find("rewrite");
|
||||
if (rsit != o.end())
|
||||
{
|
||||
CHECK(
|
||||
rsit->value().is_array(),
|
||||
"rewrite rules should be an array");
|
||||
auto& rs = rsit->value().as_array();
|
||||
for (auto& rv: rs)
|
||||
{
|
||||
CHECK(
|
||||
rv.is_object(),
|
||||
"individual rewrite rule should be an object");
|
||||
json::object& r = rv.as_object();
|
||||
|
||||
// Look for match
|
||||
auto mit = r.find("match");
|
||||
CHECK(
|
||||
mit != r.end(),
|
||||
"rewrite rule should have a match field");
|
||||
CHECK(
|
||||
mit->value().is_object() || mit->value().is_string(),
|
||||
"rewrite match field is not an object");
|
||||
if (!url_match(mit->value(), u))
|
||||
continue;
|
||||
|
||||
// Apply replacement rule
|
||||
auto uit = r.find("url");
|
||||
CHECK(
|
||||
uit != r.end(),
|
||||
"rewrite rule should have a url field");
|
||||
CHECK(
|
||||
uit->value().is_object() ||
|
||||
uit->value().is_string(),
|
||||
"url field must be an object or string");
|
||||
|
||||
if (uit->value().is_string())
|
||||
{
|
||||
json::string& uo = uit->value().as_string();
|
||||
auto ru1 = urls::parse_uri(uo);
|
||||
CHECK(ru1, "url " << uo.c_str() << " is invalid");
|
||||
u = *ru;
|
||||
}
|
||||
else
|
||||
{
|
||||
json::object& uo = uit->value().as_object();
|
||||
auto it = uo.find("protocol");
|
||||
if (it != uo.end())
|
||||
{
|
||||
CHECK(
|
||||
it->value().is_string(),
|
||||
"protocol field should be a string");
|
||||
u.set_scheme(it->value().as_string());
|
||||
}
|
||||
|
||||
it = uo.find("authority");
|
||||
if (it != uo.end())
|
||||
{
|
||||
CHECK(
|
||||
it->value().is_string(),
|
||||
"authority field should be a string");
|
||||
u.set_encoded_authority(
|
||||
it->value().as_string().subview());
|
||||
}
|
||||
|
||||
it = uo.find("username");
|
||||
if (it == uo.end())
|
||||
it = uo.find("user");
|
||||
if (it != uo.end())
|
||||
{
|
||||
CHECK(
|
||||
it->value().is_string(),
|
||||
"username field should be a string");
|
||||
u.set_encoded_user(
|
||||
it->value().as_string().subview());
|
||||
}
|
||||
|
||||
it = uo.find("password");
|
||||
if (it != uo.end())
|
||||
{
|
||||
CHECK(
|
||||
it->value().is_string(),
|
||||
"password field should be a string");
|
||||
u.set_encoded_password(
|
||||
it->value().as_string().subview());
|
||||
}
|
||||
|
||||
it = uo.find("userinfo");
|
||||
if (it != uo.end())
|
||||
{
|
||||
CHECK(
|
||||
it->value().is_string(),
|
||||
"userinfo field should be a string");
|
||||
u.set_encoded_userinfo(
|
||||
it->value().as_string().subview());
|
||||
}
|
||||
|
||||
it = uo.find("host");
|
||||
if (it != uo.end())
|
||||
{
|
||||
CHECK(
|
||||
it->value().is_string(),
|
||||
"host field should be a string");
|
||||
u.set_encoded_host(
|
||||
it->value().as_string().subview());
|
||||
}
|
||||
|
||||
it = uo.find("port");
|
||||
if (it != uo.end())
|
||||
{
|
||||
CHECK(
|
||||
it->value().is_string(),
|
||||
"port field should be a string");
|
||||
u.set_port(
|
||||
it->value().as_string().subview());
|
||||
}
|
||||
|
||||
it = uo.find("path");
|
||||
if (it == uo.end())
|
||||
it = uo.find("pathname");
|
||||
if (it != uo.end())
|
||||
{
|
||||
CHECK(
|
||||
it->value().is_string(),
|
||||
"path field should be a string");
|
||||
u.set_encoded_path(
|
||||
it->value().as_string().subview());
|
||||
}
|
||||
|
||||
it = uo.find("query");
|
||||
if (it == uo.end())
|
||||
it = uo.find("search");
|
||||
if (it != uo.end())
|
||||
{
|
||||
CHECK(
|
||||
it->value().is_string(),
|
||||
"query field should be a string");
|
||||
u.set_encoded_query(
|
||||
it->value().as_string().subview());
|
||||
}
|
||||
|
||||
it = uo.find("fragment");
|
||||
if (it == uo.end())
|
||||
it = uo.find("hash");
|
||||
if (it != uo.end())
|
||||
{
|
||||
CHECK(
|
||||
it->value().is_string(),
|
||||
"fragment field should be a string");
|
||||
u.set_encoded_fragment(
|
||||
it->value().as_string().subview());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine which browser should handle the url
|
||||
auto hsit = o.find("handlers");
|
||||
if (hsit != o.end())
|
||||
{
|
||||
CHECK(
|
||||
hsit->value().is_array(),
|
||||
"handler rules should be an array");
|
||||
auto& hs = hsit->value().as_array();
|
||||
for (auto& hv: hs)
|
||||
{
|
||||
CHECK(
|
||||
hv.is_object(),
|
||||
"individual handlers should be an object");
|
||||
json::object& h = hv.as_object();
|
||||
|
||||
auto mit = h.find("match");
|
||||
CHECK(
|
||||
mit != h.end(),
|
||||
"handle rule should have a match field");
|
||||
CHECK(
|
||||
mit->value().is_string() || mit->value().is_array(),
|
||||
"handle match field must be an array or a string");
|
||||
|
||||
auto hbit = h.find("browser");
|
||||
CHECK(
|
||||
hbit != h.end(),
|
||||
"handle rule should have a browser field");
|
||||
CHECK(
|
||||
hbit->value().is_string(),
|
||||
"browser field is not a string");
|
||||
|
||||
// Look for match and change browser
|
||||
if (url_match(mit->value(), u))
|
||||
{
|
||||
browser = hbit->value().as_string().subview();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print command finicky would run
|
||||
std::cout << "\"" << browser.c_str() << "\" " << u << '\n';
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
24
doc/modules/ROOT/pages/examples/index.adoc
Normal file
24
doc/modules/ROOT/pages/examples/index.adoc
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/url
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
= Examples
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
733
doc/modules/ROOT/pages/examples/magnet-link.adoc
Normal file
733
doc/modules/ROOT/pages/examples/magnet-link.adoc
Normal file
@@ -0,0 +1,733 @@
|
||||
//
|
||||
// Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/url
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
= Magnet Link
|
||||
|
||||
`magnet` is a URL scheme for identifying files by their content. These files are
|
||||
usually identified by cryptographic hash value.
|
||||
|
||||
Magnet links are useful in peer-to-peer file sharing networks because they allow
|
||||
resources to be referred to without the need for a continuously available host..
|
||||
|
||||
This example parses a magnet link into a new view type and prints its components to
|
||||
standard output.
|
||||
|
||||
// example_magnet
|
||||
[source,cpp]
|
||||
----
|
||||
|
||||
/*
|
||||
This example parses a magnet link into a new
|
||||
view type and prints its components to
|
||||
standard output.
|
||||
*/
|
||||
|
||||
#include <boost/url/url_view.hpp>
|
||||
#include <boost/url/url.hpp>
|
||||
#include <boost/url/optional.hpp>
|
||||
#include <boost/url/parse.hpp>
|
||||
#include <boost/url/pct_string_view.hpp>
|
||||
#include <boost/url/rfc/absolute_uri_rule.hpp>
|
||||
#include <boost/url/grammar/digit_chars.hpp>
|
||||
#include <boost/url/grammar/parse.hpp>
|
||||
#include <boost/core/detail/string_view.hpp>
|
||||
#include "filter_view.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace urls = boost::urls;
|
||||
namespace core = boost::core;
|
||||
|
||||
/** Callable to identify a magnet "exact topic"
|
||||
|
||||
This callable evaluates if a query parameter
|
||||
represents a magnet "exact topic".
|
||||
|
||||
This callable is used as a filter for
|
||||
the topics_view.
|
||||
*/
|
||||
struct is_exact_topic
|
||||
{
|
||||
bool
|
||||
operator()(urls::param_view p);
|
||||
};
|
||||
|
||||
/** Callable to identify a magnet url parameter
|
||||
|
||||
This callable evaluates if a query parameter
|
||||
has a given key and a url as its value.
|
||||
|
||||
These urls are percent-encoded twice,
|
||||
which means we need to decode it once
|
||||
before attempting to parse it.
|
||||
|
||||
This callable is used as a filter for
|
||||
the keys_view.
|
||||
*/
|
||||
class is_url_with_key
|
||||
{
|
||||
core::string_view k_;
|
||||
public:
|
||||
is_url_with_key(
|
||||
core::string_view key)
|
||||
: k_(key) {}
|
||||
|
||||
bool
|
||||
operator()(urls::param_view p);
|
||||
};
|
||||
|
||||
/** Callable to convert param values to urls
|
||||
|
||||
This callable converts the value of a
|
||||
query parameter into a urls::url_view.
|
||||
|
||||
This callable is used as a transform
|
||||
function for the topics_view.
|
||||
*/
|
||||
struct param_view_to_url
|
||||
{
|
||||
urls::url
|
||||
operator()(urls::param_view p);
|
||||
};
|
||||
|
||||
/** Callable to convert param values to std::string
|
||||
|
||||
This callable converts the value of a
|
||||
query parameter into a std::string.
|
||||
|
||||
This callable is used as a transform
|
||||
function for the keys_view.
|
||||
*/
|
||||
struct to_decoded_value
|
||||
{
|
||||
std::string
|
||||
operator()(urls::param_view p)
|
||||
{
|
||||
return p.value;
|
||||
}
|
||||
};
|
||||
|
||||
/** Callable to convert param values to info_hashes
|
||||
|
||||
This callable converts the value of a
|
||||
query parameter into a core::string_view with
|
||||
its infohash.
|
||||
|
||||
The infohash hash is a parameter of an
|
||||
exact topic field in the magnet link.
|
||||
|
||||
This callable is used as a transform
|
||||
function for the info_hashes_view.
|
||||
*/
|
||||
struct param_view_to_infohash
|
||||
{
|
||||
core::string_view
|
||||
operator()(urls::param_view p);
|
||||
};
|
||||
|
||||
/** Callable to convert param values to protocols
|
||||
|
||||
This callable converts the value of a
|
||||
query parameter into a core::string_view with
|
||||
its protocol.
|
||||
|
||||
The protocol is a parameter of an exact
|
||||
topic field in the magnet link.
|
||||
|
||||
This callable is used as a transform
|
||||
function for the protocols_view.
|
||||
*/
|
||||
struct to_protocol
|
||||
{
|
||||
core::string_view
|
||||
operator()(urls::param_view p);
|
||||
};
|
||||
|
||||
struct magnet_link_rule_t;
|
||||
|
||||
/** A new url type for magnet links
|
||||
|
||||
This class represents a reference to a
|
||||
magnet link.
|
||||
|
||||
Unlike a urls::url_view, which only represents the
|
||||
general syntax of urls, a magnet_link_view
|
||||
represents a reference to fields that are
|
||||
relevant to magnet links, while ignoring
|
||||
elements of the general syntax
|
||||
that are not relevant to the scheme.
|
||||
|
||||
This allows us to use the general syntax
|
||||
parsers to create a representation that
|
||||
is more appropriate for the specified scheme
|
||||
syntax.
|
||||
|
||||
@par Specification
|
||||
@li <a href="https://www.bittorrent.org/beps/bep_0005.html"
|
||||
>DHT Protocol</a>
|
||||
@li <a href="https://www.bittorrent.org/beps/bep_0009.html"
|
||||
>Extension for Peers to Send Metadata Files</a>
|
||||
@li <a href="https://www.bittorrent.org/beps/bep_0053.html"
|
||||
>Magnet URI extension</a>
|
||||
@li <a href="https://en.wikipedia.org/wiki/Magnet_URI_scheme"
|
||||
>Magnet URI scheme</a>
|
||||
|
||||
@par References
|
||||
@li <a href="https://github.com/webtorrent/magnet-uri"
|
||||
>magnet-uri</a>
|
||||
|
||||
*/
|
||||
class magnet_link_view
|
||||
{
|
||||
urls::url_view u_;
|
||||
|
||||
public:
|
||||
/// A view of all exact topics in the magnet_link
|
||||
using topics_view =
|
||||
filter_view<
|
||||
urls::params_view,
|
||||
urls::url,
|
||||
is_exact_topic,
|
||||
param_view_to_url>;
|
||||
|
||||
/// A view of all info_hashes in the magnet_link
|
||||
using info_hashes_view =
|
||||
filter_view<
|
||||
urls::params_view,
|
||||
std::string,
|
||||
is_exact_topic,
|
||||
param_view_to_infohash>;
|
||||
|
||||
/// A view of all protocols in the magnet_link
|
||||
using protocols_view =
|
||||
filter_view<
|
||||
urls::params_view,
|
||||
std::string,
|
||||
is_exact_topic,
|
||||
to_protocol>;
|
||||
|
||||
/** A view of all urls with the specified key in the magnet_link
|
||||
|
||||
A number of fields in a magnet link refer
|
||||
to a list of urls with the same query
|
||||
parameter keys.
|
||||
*/
|
||||
using keys_view =
|
||||
filter_view<
|
||||
urls::params_view,
|
||||
std::string,
|
||||
is_url_with_key,
|
||||
to_decoded_value>;
|
||||
|
||||
/** URNs to the file or files hashes
|
||||
|
||||
An exact topic is the main field of a
|
||||
magnet link. A magnet link must contain
|
||||
one or more exact topics with the query
|
||||
key "xt" or ["xt.1", "xt.2", ...].
|
||||
|
||||
The value of each exact topic is a URN
|
||||
representing the file hash and the protocol
|
||||
to access the file.
|
||||
|
||||
@return A view of all exact topic URNs in the link
|
||||
*/
|
||||
topics_view
|
||||
exact_topics() const noexcept;
|
||||
|
||||
/** Info hash of the file or files
|
||||
|
||||
@return A view of all info hashes in exact topics
|
||||
*/
|
||||
info_hashes_view
|
||||
info_hashes() const noexcept;
|
||||
|
||||
/** Protocol of the exact topics
|
||||
|
||||
@return A view of all protocols in exact topics
|
||||
*/
|
||||
protocols_view
|
||||
protocols() const noexcept;
|
||||
|
||||
/** Return view of address trackers
|
||||
|
||||
A tracker URL is used to obtain resources
|
||||
for BitTorrent downloads.
|
||||
|
||||
@return A view of all address trackers in the link
|
||||
*/
|
||||
keys_view
|
||||
address_trackers() const;
|
||||
|
||||
/** Return view of exact sources
|
||||
|
||||
An exact source URL is a direct download
|
||||
link to the file.
|
||||
|
||||
@return A view of all exact sources
|
||||
*/
|
||||
keys_view
|
||||
exact_sources() const;
|
||||
|
||||
/** Return view of acceptable sources
|
||||
|
||||
An acceptable source URL is a direct
|
||||
download link to the file that can be
|
||||
used as a fallback for exact sources.
|
||||
|
||||
@return A view of all acceptable sources
|
||||
*/
|
||||
keys_view
|
||||
acceptable_sources() const;
|
||||
|
||||
/** Return keyword topic
|
||||
|
||||
The keyword topic is the search keywords
|
||||
to use in P2P networks.
|
||||
|
||||
@par Example
|
||||
kt=martin+luther+king+mp3
|
||||
|
||||
@return Keyword topic
|
||||
*/
|
||||
boost::optional<std::string>
|
||||
keyword_topic() const noexcept;
|
||||
|
||||
/** Return manifest topics
|
||||
|
||||
This function returns a link to the
|
||||
metafile that contains a list of magneto.
|
||||
|
||||
@par Specification
|
||||
@li <a href="http://rakjar.de/gnuticles/MAGMA-Specsv22.txt"
|
||||
>MAGnet MAnifest</a>
|
||||
|
||||
@return A view of manifest topics
|
||||
*/
|
||||
keys_view
|
||||
manifest_topics() const;
|
||||
|
||||
/** Return display name
|
||||
|
||||
This function returns a filename to
|
||||
display to the user. This field is
|
||||
only used for convenience.
|
||||
|
||||
@par Specification
|
||||
@li <a href="http://rakjar.de/gnuticles/MAGMA-Specsv22.txt"
|
||||
>MAGnet MAnifest</a>
|
||||
|
||||
@return Display name
|
||||
*/
|
||||
boost::optional<urls::pct_string_view>
|
||||
display_name() const noexcept;
|
||||
|
||||
/** Return web seed
|
||||
|
||||
The web seed represents the payload data
|
||||
served over HTTP(S).
|
||||
|
||||
@return Web seed
|
||||
*/
|
||||
keys_view
|
||||
web_seed() const;
|
||||
|
||||
/** Return extra supplement parameter
|
||||
|
||||
This function returns informal options
|
||||
and parameters of the magnet link.
|
||||
|
||||
Query parameters whose keys have the
|
||||
prefix "x." are used in magnet links
|
||||
for extra parameters. These names
|
||||
are guaranteed to never be standardized.
|
||||
|
||||
@par Example
|
||||
x.parameter_name=parameter_data
|
||||
|
||||
@return Web seed
|
||||
*/
|
||||
boost::optional<urls::pct_string_view>
|
||||
param(core::string_view key) const noexcept;
|
||||
|
||||
friend
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, magnet_link_view m)
|
||||
{
|
||||
return os << m.u_;
|
||||
}
|
||||
|
||||
private:
|
||||
// get a query parameter as a urls::pct_string_view
|
||||
boost::optional<urls::pct_string_view>
|
||||
encoded_param(core::string_view key) const noexcept;
|
||||
|
||||
// get a query parameter as a urls::url_view
|
||||
boost::optional<urls::url_view>
|
||||
url_param(core::string_view key) const noexcept;
|
||||
|
||||
friend magnet_link_rule_t;
|
||||
};
|
||||
|
||||
bool
|
||||
is_exact_topic::
|
||||
operator()(urls::param_view p)
|
||||
{
|
||||
// These comparisons use the lazy
|
||||
// operator== for urls::pct_string_view
|
||||
// For instance, the comparison also works
|
||||
// if the underlying key is "%78%74"/
|
||||
if (p.key == "xt")
|
||||
return true;
|
||||
return
|
||||
p.key.size() > 3 &&
|
||||
*std::next(p.key.begin(), 0) == 'x' &&
|
||||
*std::next(p.key.begin(), 1) == 't' &&
|
||||
*std::next(p.key.begin(), 2) == '.' &&
|
||||
std::all_of(
|
||||
std::next(p.key.begin(), 3),
|
||||
p.key.end(),
|
||||
urls::grammar::digit_chars);
|
||||
}
|
||||
|
||||
bool
|
||||
is_url_with_key::
|
||||
operator()(urls::param_view p)
|
||||
{
|
||||
if (p.key != k_)
|
||||
return false;
|
||||
boost::system::error_code ec;
|
||||
std::string buf(
|
||||
p.value.begin(), p.value.end());
|
||||
if (ec.failed())
|
||||
return false;
|
||||
boost::system::result<urls::url_view> r =
|
||||
urls::parse_uri(buf);
|
||||
return r.has_value();
|
||||
}
|
||||
|
||||
urls::url
|
||||
param_view_to_url::
|
||||
operator()(urls::param_view p)
|
||||
{
|
||||
// `param_view_to_url` is used in topics_view,
|
||||
// where the URL is not
|
||||
// percent-encoded twice.
|
||||
// Thus, we can already parse the
|
||||
// encoded value.
|
||||
auto ur =
|
||||
urls::parse_uri(p.value);
|
||||
BOOST_ASSERT(ur);
|
||||
urls::url u = *ur;
|
||||
return u;
|
||||
}
|
||||
|
||||
core::string_view
|
||||
param_view_to_infohash::
|
||||
operator()(urls::param_view p)
|
||||
{
|
||||
urls::url_view topic =
|
||||
urls::parse_uri(p.value).value();
|
||||
core::string_view t = topic.encoded_path();
|
||||
std::size_t pos = t.find_last_of(':');
|
||||
if (pos != core::string_view::npos)
|
||||
return t.substr(pos + 1);
|
||||
return t;
|
||||
}
|
||||
|
||||
core::string_view
|
||||
to_protocol::
|
||||
operator()(urls::param_view p)
|
||||
{
|
||||
urls::url_view topic =
|
||||
urls::parse_uri(p.value).value();
|
||||
core::string_view t = topic.encoded_path();
|
||||
std::size_t pos = t.find_last_of(':');
|
||||
return t.substr(0, pos);
|
||||
}
|
||||
|
||||
auto
|
||||
magnet_link_view::exact_topics() const noexcept
|
||||
-> topics_view
|
||||
{
|
||||
return {u_.params()};
|
||||
}
|
||||
|
||||
auto
|
||||
magnet_link_view::info_hashes() const noexcept
|
||||
-> info_hashes_view
|
||||
{
|
||||
return {u_.params()};
|
||||
}
|
||||
|
||||
auto
|
||||
magnet_link_view::protocols() const noexcept
|
||||
-> protocols_view
|
||||
{
|
||||
return {u_.params()};
|
||||
}
|
||||
|
||||
auto
|
||||
magnet_link_view::address_trackers() const
|
||||
-> keys_view
|
||||
{
|
||||
return {
|
||||
u_.params(),
|
||||
is_url_with_key{"tr"}};
|
||||
}
|
||||
|
||||
auto
|
||||
magnet_link_view::exact_sources() const
|
||||
-> keys_view
|
||||
{
|
||||
return {
|
||||
u_.params(),
|
||||
is_url_with_key{"xs"}};
|
||||
}
|
||||
|
||||
auto
|
||||
magnet_link_view::acceptable_sources() const
|
||||
-> keys_view
|
||||
{
|
||||
return {
|
||||
u_.params(),
|
||||
is_url_with_key{"as"}};
|
||||
}
|
||||
|
||||
boost::optional<std::string>
|
||||
magnet_link_view::keyword_topic() const noexcept
|
||||
{
|
||||
boost::optional<urls::pct_string_view> o =
|
||||
encoded_param("kt");
|
||||
if (o)
|
||||
return o->decode();
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
auto
|
||||
magnet_link_view::manifest_topics() const
|
||||
-> keys_view
|
||||
{
|
||||
return {
|
||||
u_.params(),
|
||||
is_url_with_key{"mt"}};
|
||||
}
|
||||
|
||||
boost::optional<urls::pct_string_view>
|
||||
magnet_link_view::display_name() const noexcept
|
||||
{
|
||||
return encoded_param("dn");
|
||||
}
|
||||
|
||||
auto
|
||||
magnet_link_view::web_seed() const
|
||||
-> keys_view
|
||||
{
|
||||
return {
|
||||
u_.params(),
|
||||
is_url_with_key{"ws"}};
|
||||
}
|
||||
|
||||
boost::optional<urls::pct_string_view>
|
||||
magnet_link_view::param(core::string_view key) const noexcept
|
||||
{
|
||||
urls::params_view ps = u_.params();
|
||||
auto it = ps.begin();
|
||||
auto end = ps.end();
|
||||
while (it != end)
|
||||
{
|
||||
urls::param_view p = *it;
|
||||
if (p.key.size() < 2)
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
auto first = p.key.begin();
|
||||
auto mid = std::next(p.key.begin(), 2);
|
||||
auto last = p.key.end();
|
||||
urls::pct_string_view prefix(
|
||||
core::string_view(first, mid));
|
||||
urls::pct_string_view suffix(
|
||||
core::string_view(mid, last));
|
||||
if (prefix == "x." &&
|
||||
suffix == key &&
|
||||
p.has_value)
|
||||
return urls::pct_string_view(p.value);
|
||||
++it;
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
boost::optional<urls::pct_string_view>
|
||||
magnet_link_view::encoded_param(core::string_view key) const noexcept
|
||||
{
|
||||
urls::params_encoded_view ps = u_.encoded_params();
|
||||
auto it = ps.find(key);
|
||||
if (it != ps.end() && (*it).has_value)
|
||||
return urls::pct_string_view((*it).value);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
boost::optional<urls::url_view>
|
||||
magnet_link_view::url_param(core::string_view key) const noexcept
|
||||
{
|
||||
urls::params_encoded_view ps = u_.encoded_params();
|
||||
auto it = ps.find(key);
|
||||
if (it != ps.end() && (*it).has_value)
|
||||
{
|
||||
boost::system::result<urls::url_view> r =
|
||||
urls::parse_uri((*it).value);
|
||||
if (r)
|
||||
return *r;
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
/** Rule to match a magnet link
|
||||
*/
|
||||
struct magnet_link_rule_t
|
||||
{
|
||||
/// Value type returned by the rule
|
||||
using value_type = magnet_link_view;
|
||||
|
||||
/// Parse a sequence of characters into a magnet_link_view
|
||||
boost::system::result< value_type >
|
||||
parse( char const*& it, char const* end ) const noexcept;
|
||||
};
|
||||
|
||||
auto
|
||||
magnet_link_rule_t::parse(
|
||||
char const*& it,
|
||||
char const* end ) const noexcept
|
||||
-> boost::system::result< value_type >
|
||||
{
|
||||
// 1) Parse url with the general uri syntax
|
||||
boost::system::result<urls::url_view> r =
|
||||
urls::grammar::parse(it, end, urls::absolute_uri_rule);
|
||||
if(!r)
|
||||
return urls::grammar::error::invalid;
|
||||
magnet_link_view m;
|
||||
m.u_ = *r;
|
||||
|
||||
// 2) Check if exact topics are valid urls
|
||||
// and that we have at least one. This is the
|
||||
// only mandatory field in magnet links.
|
||||
auto ps = m.u_.params();
|
||||
auto pit = ps.begin();
|
||||
auto pend = ps.end();
|
||||
pit = std::find_if(pit, pend, is_exact_topic{});
|
||||
if (pit == pend)
|
||||
{
|
||||
// no exact topic in the magnet link
|
||||
return urls::grammar::error::invalid;
|
||||
}
|
||||
|
||||
// all topics should parse as valid urls
|
||||
if (!std::all_of(pit, pend, [](
|
||||
urls::param_view p)
|
||||
{
|
||||
if (!is_exact_topic{}(p))
|
||||
return true;
|
||||
boost::system::result<urls::url_view> u =
|
||||
urls::parse_uri(p.value);
|
||||
return u.has_value();
|
||||
}))
|
||||
return urls::grammar::error::invalid;
|
||||
|
||||
// all other fields are optional
|
||||
// magnet link is OK
|
||||
return m;
|
||||
}
|
||||
|
||||
constexpr magnet_link_rule_t magnet_link_rule{};
|
||||
|
||||
/** Return a parsed magnet link from a string, or error.
|
||||
|
||||
This is a more convenient user-facing function
|
||||
to parse magnet links.
|
||||
*/
|
||||
boost::system::result< magnet_link_view >
|
||||
parse_magnet_link( core::string_view s ) noexcept
|
||||
{
|
||||
return urls::grammar::parse(s, magnet_link_rule);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// This example shows how to use custom parsing
|
||||
// to process alternate URI schemes, in this
|
||||
// case "magnet"
|
||||
if (argc != 2) {
|
||||
std::cout << argv[0] << "\n";
|
||||
std::cout << "magnet <link>\n"
|
||||
"example: magnet magnet:?xt=urn:btih:d2474e86c95b19b8bcfdb92bc12c9d44667cfa36"
|
||||
"&dn=Leaves+of+Grass+by+Walt+Whitman.epub"
|
||||
"&tr=udp%3A%2F%2Ftracker.example4.com%3A80"
|
||||
"&tr=udp%3A%2F%2Ftracker.example5.com%3A80"
|
||||
"&tr=udp%3A%2F%2Ftracker.example3.com%3A6969"
|
||||
"&tr=udp%3A%2F%2Ftracker.example2.com%3A80"
|
||||
"&tr=udp%3A%2F%2Ftracker.example1.com%3A1337\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
boost::system::result<magnet_link_view> r =
|
||||
parse_magnet_link(argv[1]);
|
||||
if (!r)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
magnet_link_view m = *r;
|
||||
std::cout << "link: " << m << "\n";
|
||||
|
||||
auto xt = m.exact_topics();
|
||||
for (auto h : xt)
|
||||
std::cout << "topic: " << h << "\n";
|
||||
|
||||
auto hs = m.info_hashes();
|
||||
for (auto h : hs)
|
||||
std::cout << "hash: " << h << "\n";
|
||||
|
||||
auto ps = m.protocols();
|
||||
for (auto p : ps)
|
||||
std::cout << "protocol: " << p << "\n";
|
||||
|
||||
auto tr = m.address_trackers();
|
||||
for (auto h : tr)
|
||||
std::cout << "tracker: " << h << "\n";
|
||||
|
||||
auto xs = m.exact_sources();
|
||||
for (auto x : xs)
|
||||
std::cout << "exact source: " << x << "\n";
|
||||
|
||||
auto as = m.acceptable_sources();
|
||||
for (auto a : as)
|
||||
std::cout << "topic: " << a << "\n";
|
||||
|
||||
auto mt = m.manifest_topics();
|
||||
for (auto a : mt)
|
||||
std::cout << "manifest topic: " << a << "\n";
|
||||
|
||||
auto ws = m.web_seed();
|
||||
for (auto a : ws)
|
||||
std::cout << "web seed: " << a << "\n";
|
||||
|
||||
auto kt = m.keyword_topic();
|
||||
if (kt)
|
||||
std::cout << "keyword topic: " << *kt << "\n";
|
||||
|
||||
auto dn = m.display_name();
|
||||
if (dn)
|
||||
std::cout << "display name: " << *dn << "\n";
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
428
doc/modules/ROOT/pages/examples/mailto.adoc
Normal file
428
doc/modules/ROOT/pages/examples/mailto.adoc
Normal file
@@ -0,0 +1,428 @@
|
||||
//
|
||||
// Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/url
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
= mailto URLs
|
||||
|
||||
`mailto` is a URL scheme for email addresses. `mailto` URL are used on websites
|
||||
to allow users to send an email to a specific address directly from an HTML document.
|
||||
|
||||
This example parses a mailto URL into a new view type and prints its components to
|
||||
standard output.
|
||||
|
||||
// example_mailto
|
||||
[source,cpp]
|
||||
----
|
||||
|
||||
/*
|
||||
This example parses a mailto URL into a new
|
||||
view type and prints its components to
|
||||
standard output.
|
||||
*/
|
||||
|
||||
#include <boost/url/grammar/ci_string.hpp>
|
||||
#include <boost/url/grammar/parse.hpp>
|
||||
#include <boost/url/optional.hpp>
|
||||
#include <boost/url/rfc/absolute_uri_rule.hpp>
|
||||
#include <boost/url/url.hpp>
|
||||
#include <boost/url/url_view.hpp>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include "rfc.hpp"
|
||||
|
||||
namespace urls = boost::urls;
|
||||
|
||||
// fwd-declaration for mailto_view
|
||||
struct mailto_rule_t;
|
||||
|
||||
/// A new url type for mailto URLs
|
||||
/**
|
||||
This class represents a URI with the mailto
|
||||
scheme.
|
||||
|
||||
Unlike a urls::url_view, which only represents
|
||||
the general syntax of urls, a mailto_view
|
||||
represents a reference to fields that are
|
||||
relevant to mailto URLs, while ignoring
|
||||
elements of the general syntax
|
||||
that are not relevant to the scheme.
|
||||
|
||||
This allows us to use the general syntax
|
||||
parsers to create a representation that
|
||||
is more appropriate for the specified scheme
|
||||
syntax.
|
||||
|
||||
@par Specification
|
||||
@li <a href="https://www.rfc-editor.org/rfc/rfc6068"
|
||||
>The 'mailto' URI Scheme</a>
|
||||
@li <a href="https://www.rfc-editor.org/errata/rfc6068"
|
||||
>RFC Errata Report</a>
|
||||
|
||||
@par References
|
||||
@li <a href="https://en.wikipedia.org/wiki/Mailto"
|
||||
>mailto (Wikipedia)</a>
|
||||
|
||||
*/
|
||||
class mailto_view
|
||||
{
|
||||
urls::url_view u_;
|
||||
|
||||
public:
|
||||
/// Return the specified email address in the URL
|
||||
/**
|
||||
A mailto URL might contain multiple email
|
||||
addresses separated by commas.
|
||||
|
||||
The first addresses are represented in
|
||||
the path. Other addresses are in
|
||||
any query parameter whose key is "to".
|
||||
|
||||
@param i Address index
|
||||
|
||||
@return The specified address
|
||||
*/
|
||||
std::string
|
||||
address(std::size_t i = 0) const;
|
||||
|
||||
/// @copydoc address()
|
||||
urls::pct_string_view
|
||||
encoded_address(std::size_t i = 0) const noexcept;
|
||||
|
||||
/// Return number of email addresses in the URL
|
||||
std::size_t
|
||||
size() const noexcept;
|
||||
|
||||
/// Return the specified cc email address in the URL
|
||||
/**
|
||||
A mailto URL might contain multiple cc
|
||||
email addresses separated by commas.
|
||||
|
||||
Addresses can be represented in any query
|
||||
parameter whose key is "cc".
|
||||
|
||||
@param i Address index
|
||||
|
||||
@return The specified cc address
|
||||
*/
|
||||
std::string
|
||||
cc(std::size_t i) const;
|
||||
|
||||
/// @copydoc cc()
|
||||
urls::pct_string_view
|
||||
encoded_cc(std::size_t i) const noexcept;
|
||||
|
||||
/// Return number of "cc" email addresses in the URL
|
||||
std::size_t
|
||||
size_cc() const noexcept;
|
||||
|
||||
/// Return email message subject
|
||||
std::string
|
||||
subject() const;
|
||||
|
||||
/// @copydoc subject()
|
||||
urls::pct_string_view
|
||||
encoded_subject() const noexcept;
|
||||
|
||||
/// Return email message body
|
||||
std::string
|
||||
body() const;
|
||||
|
||||
/// @copydoc body()
|
||||
urls::pct_string_view
|
||||
encoded_body() const noexcept;
|
||||
|
||||
friend
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, mailto_view m)
|
||||
{
|
||||
return os << m.u_;
|
||||
}
|
||||
|
||||
private:
|
||||
// Count number of addresses in a string
|
||||
static
|
||||
std::size_t
|
||||
addr_in_str(boost::core::string_view s);
|
||||
|
||||
// Get the ith address from a string
|
||||
static
|
||||
boost::optional<urls::pct_string_view>
|
||||
get_nth_address(boost::core::string_view to, std::size_t &i) noexcept;
|
||||
|
||||
// Get param value or empty otherwise
|
||||
urls::pct_string_view
|
||||
param_or_empty(urls::pct_string_view k) const noexcept;
|
||||
|
||||
friend mailto_rule_t;
|
||||
};
|
||||
|
||||
/** Rule to match a mailto URL
|
||||
*/
|
||||
struct mailto_rule_t
|
||||
{
|
||||
/// Value type returned by the rule
|
||||
using value_type = mailto_view;
|
||||
|
||||
/// Parse a sequence of characters into a mailto_view
|
||||
boost::system::result< value_type >
|
||||
parse( char const*& it, char const* end ) const noexcept;
|
||||
};
|
||||
|
||||
constexpr mailto_rule_t mailto_rule{};
|
||||
|
||||
/** Return a parsed mailto URL from a string, or error.
|
||||
|
||||
This is a more convenient user-facing function
|
||||
to parse mailto URLs.
|
||||
*/
|
||||
boost::system::result< mailto_view >
|
||||
parse_mailto( boost::core::string_view s ) noexcept
|
||||
{
|
||||
return urls::grammar::parse(s, mailto_rule);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// This example shows how to use custom parsing
|
||||
// to process alternate URI schemes, in this
|
||||
// case "mailto"
|
||||
if (argc != 2) {
|
||||
std::cout << argv[0] << "\n";
|
||||
std::cout << "mailto <URL>\n"
|
||||
"examples:\n"
|
||||
// Single e-mail address
|
||||
"mailto mailto:someone@example.com\n"
|
||||
// Two e-mail addresses
|
||||
"mailto mailto:someone@example.com,someoneelse@example.com\n"
|
||||
// E-mail headers
|
||||
"mailto mailto:someone@example.com?subject=Our%20meeting&cc=someone_else@example.com&body=Hi%21\n"
|
||||
// E-mail headers only
|
||||
"mailto mailto:?to=&subject=mailto%20example&body=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FMailto\n"
|
||||
// All fields
|
||||
"mailto mailto:someone@example.com,%73omeoneelse@me.com?to=thirdperson@example.com&subject=Our%20meeting&cc=someone_else@example.com,onemore@ex%61mple.com&body=Hi%21\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
boost::system::result<mailto_view> r =
|
||||
parse_mailto(argv[1]);
|
||||
if (!r)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
mailto_view m = *r;
|
||||
std::cout << "link: " << m << "\n";
|
||||
|
||||
for (std::size_t i = 0; i < m.size(); ++i)
|
||||
std::cout <<
|
||||
"to[" << i << "]: " <<
|
||||
m.address(i) << "\n";
|
||||
|
||||
for (std::size_t i = 0; i < m.size_cc(); ++i)
|
||||
std::cout <<
|
||||
"cc[" << i << "]: " <<
|
||||
m.address(i) << "\n";
|
||||
|
||||
std::cout << "subject: " << m.subject() << "\n";
|
||||
std::cout << "body: " << m.body() << "\n";
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
std::string
|
||||
mailto_view::address(std::size_t i) const
|
||||
{
|
||||
return encoded_address(i).decode();
|
||||
}
|
||||
|
||||
urls::pct_string_view
|
||||
mailto_view::encoded_address(std::size_t i) const noexcept
|
||||
{
|
||||
// Look for ith email address in the path string
|
||||
auto s = get_nth_address(u_.encoded_path(), i);
|
||||
if (s)
|
||||
return *s;
|
||||
|
||||
// Look for ith email address in one of the "to" headers
|
||||
auto ps = u_.encoded_params();
|
||||
auto it = ps.find("to", urls::ignore_case);
|
||||
while (it != ps.end())
|
||||
{
|
||||
s = get_nth_address((*it++).value, i);
|
||||
if (s)
|
||||
return *s;
|
||||
it = ps.find(it, "to", urls::ignore_case);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::size_t
|
||||
mailto_view::size() const noexcept
|
||||
{
|
||||
// Count addresses in path
|
||||
std::size_t n = addr_in_str(u_.encoded_path());
|
||||
|
||||
// Count addresses in "to" headers
|
||||
auto ps = u_.encoded_params();
|
||||
auto it = ps.find("to", urls::ignore_case);
|
||||
while (it != ps.end())
|
||||
{
|
||||
n += addr_in_str((*it++).value);
|
||||
it = ps.find(it, "to", urls::ignore_case);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
std::string
|
||||
mailto_view::cc(std::size_t i) const
|
||||
{
|
||||
return encoded_cc(i).decode();
|
||||
}
|
||||
|
||||
urls::pct_string_view
|
||||
mailto_view::encoded_cc(std::size_t i) const noexcept
|
||||
{
|
||||
// Look for ith email address in one of the "to" headers
|
||||
auto ps = u_.encoded_params();
|
||||
auto it = ps.find("cc", urls::ignore_case);
|
||||
while (it != ps.end())
|
||||
{
|
||||
auto s = get_nth_address((*it++).value, i);
|
||||
if (s)
|
||||
return *s;
|
||||
it = ps.find(it, "cc", urls::ignore_case);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::size_t
|
||||
mailto_view::size_cc() const noexcept
|
||||
{
|
||||
// Count addresses in "to" headers
|
||||
std::size_t n = 0;
|
||||
auto ps = u_.encoded_params();
|
||||
auto it = ps.find("cc", urls::ignore_case);
|
||||
while (it != ps.end())
|
||||
{
|
||||
n += addr_in_str((*it++).value);
|
||||
it = ps.find(it, "cc", urls::ignore_case);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
std::string
|
||||
mailto_view::subject() const
|
||||
{
|
||||
return encoded_subject().decode();
|
||||
}
|
||||
|
||||
urls::pct_string_view
|
||||
mailto_view::encoded_subject() const noexcept
|
||||
{
|
||||
return param_or_empty("subject");
|
||||
}
|
||||
|
||||
std::string
|
||||
mailto_view::mailto_view::body() const
|
||||
{
|
||||
return encoded_body().decode();
|
||||
}
|
||||
|
||||
urls::pct_string_view
|
||||
mailto_view::encoded_body() const noexcept
|
||||
{
|
||||
return param_or_empty("body");
|
||||
}
|
||||
|
||||
std::size_t
|
||||
mailto_view::addr_in_str(boost::core::string_view s)
|
||||
{
|
||||
std::size_t n = 0;
|
||||
bool empty = true;
|
||||
for (char c : s)
|
||||
{
|
||||
if (c == ',')
|
||||
{
|
||||
n += !empty;
|
||||
empty = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
empty = false;
|
||||
}
|
||||
}
|
||||
n += !empty;
|
||||
return n;
|
||||
}
|
||||
|
||||
boost::optional<urls::pct_string_view>
|
||||
mailto_view::get_nth_address(boost::core::string_view to, std::size_t &i) noexcept
|
||||
{
|
||||
auto p = to.find(',');
|
||||
while (p != boost::core::string_view::npos)
|
||||
{
|
||||
if (i == 0)
|
||||
return urls::pct_string_view(
|
||||
to.substr(0, p));
|
||||
--i;
|
||||
to.remove_prefix(p + 1);
|
||||
p = to.find(',');
|
||||
}
|
||||
if (!to.empty())
|
||||
{
|
||||
if (i == 0)
|
||||
return urls::pct_string_view(
|
||||
to.substr(0, p));
|
||||
--i;
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
urls::pct_string_view
|
||||
mailto_view::param_or_empty(urls::pct_string_view k) const noexcept
|
||||
{
|
||||
auto ps = u_.encoded_params();
|
||||
auto it = ps.find(k, urls::ignore_case);
|
||||
if (it != ps.end())
|
||||
return (*it).value;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto
|
||||
mailto_rule_t::parse( char const*& it, char const* end ) const noexcept
|
||||
-> boost::system::result< value_type >
|
||||
{
|
||||
// Syntax-based rules
|
||||
boost::system::result<urls::url_view> r =
|
||||
urls::grammar::parse(it, end, urls::absolute_uri_rule);
|
||||
if (!r)
|
||||
return r.error();
|
||||
|
||||
// Scheme-based rules
|
||||
mailto_view m;
|
||||
m.u_ = *r;
|
||||
auto valid_header = [](urls::param_pct_view p) {
|
||||
return
|
||||
urls::grammar::parse(p.key, hfname_rule) &&
|
||||
urls::grammar::parse(p.value, hfvalue_rule) &&
|
||||
p.has_value &&
|
||||
(!urls::grammar::ci_is_equal(p.key, "to") ||
|
||||
urls::grammar::parse(p.value, addr_spec_rule));
|
||||
};
|
||||
auto ps = m.u_.encoded_params();
|
||||
if (m.u_.scheme() == "mailto" &&
|
||||
!m.u_.has_authority() &&
|
||||
urls::grammar::parse(m.u_.encoded_path(), to_rule) &&
|
||||
std::all_of(ps.begin(), ps.end(), valid_header))
|
||||
return m;
|
||||
return urls::grammar::error::invalid;
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
105
doc/modules/ROOT/pages/examples/qrcode.adoc
Normal file
105
doc/modules/ROOT/pages/examples/qrcode.adoc
Normal file
@@ -0,0 +1,105 @@
|
||||
//
|
||||
// Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/url
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
= QR Code
|
||||
|
||||
A QR code is a machine-readable two-dimensional barcode. They might contain data
|
||||
for a identifier or a URL to a website.
|
||||
|
||||
This example shows how to construct and modify URLs to consume a third party API to
|
||||
generate QR Codes.
|
||||
|
||||
// example_qrcode
|
||||
[source,cpp]
|
||||
----
|
||||
|
||||
/*
|
||||
This example shows how to construct and modify
|
||||
URLs to consume a third party API to
|
||||
generate QR Codes.
|
||||
https://developers.google.com/chart/infographics/docs/qr_codes
|
||||
*/
|
||||
|
||||
#include <boost/url/url.hpp>
|
||||
#include <boost/core/detail/string_view.hpp>
|
||||
#include <boost/url/parse.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace urls = boost::urls;
|
||||
namespace core = boost::core;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
std::cout << argv[0] << "\n";
|
||||
std::cout << "Usage: qrcode <data> <width> <height> <output encoding> <error correction> <border>\n"
|
||||
"options:\n"
|
||||
" <data>: The data to encode (required)\n"
|
||||
" <width>: Image width (default: 100)\n"
|
||||
" <height>: Image height (default: width)\n"
|
||||
" <output encoding>: UTF-8, Shift_JIS, ISO-8859-1 (default: utf8)\n"
|
||||
" <error correction>: percentage of error correction (default: 7)\n"
|
||||
" <margin>: border width (default: 4)\n"
|
||||
"examples:\n"
|
||||
"qrcode \"Hello world\"\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
urls::url u =
|
||||
urls::parse_uri(
|
||||
"https://chart.googleapis.com/chart?cht=qr").value();
|
||||
auto ps = u.params();
|
||||
|
||||
// Data
|
||||
ps.append({"chl", argv[1]});
|
||||
|
||||
// Size
|
||||
std::size_t width = argc < 3 ? 100 : std::stoll(argv[2]);
|
||||
std::size_t height = argc < 4 ? width : std::stoll(argv[3]);
|
||||
ps.append({"chs", std::to_string(width) + "x" + std::to_string(height)});
|
||||
|
||||
// Encoding
|
||||
if (argc >= 5)
|
||||
{
|
||||
core::string_view output_encoding =
|
||||
core::string_view(argv[3]) == "Shift_JIS" ||
|
||||
core::string_view(argv[3]) == "ISO-8859-1" ?
|
||||
argv[4] : "UTF-8";
|
||||
ps.append({"choe", output_encoding});
|
||||
}
|
||||
|
||||
// Error
|
||||
if (argc >= 6)
|
||||
{
|
||||
std::size_t err = std::stoll(argv[5]);
|
||||
std::string chld;
|
||||
if (err < 11)
|
||||
chld = "L";
|
||||
else if (err < 20)
|
||||
chld = "M";
|
||||
else if (err < 27)
|
||||
chld = "Q";
|
||||
else
|
||||
chld = "H";
|
||||
std::size_t margin = argc < 7 ? 4 : std::stoll(argv[6]);
|
||||
chld += "|";
|
||||
chld += std::to_string(margin);
|
||||
ps.append({"chld", chld});
|
||||
}
|
||||
|
||||
std::cout << u << '\n';
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
333
doc/modules/ROOT/pages/examples/router.adoc
Normal file
333
doc/modules/ROOT/pages/examples/router.adoc
Normal file
@@ -0,0 +1,333 @@
|
||||
//
|
||||
// Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/url
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
= Router
|
||||
|
||||
This example defines a router for URL paths. If the specified route matches one of the existing
|
||||
routes, the example executes the underlying callback function.
|
||||
|
||||
// example_router
|
||||
[source,cpp]
|
||||
----
|
||||
|
||||
/*
|
||||
This example defines a router for URL paths.
|
||||
Each path is associated with a callback
|
||||
function.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_URL_SOURCE
|
||||
#define BOOST_URL_SOURCE
|
||||
#endif
|
||||
|
||||
#include "router.hpp"
|
||||
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
|
||||
namespace urls = boost::urls;
|
||||
namespace core = boost::core;
|
||||
namespace asio = boost::asio;
|
||||
namespace beast = boost::beast;
|
||||
namespace http = beast::http;
|
||||
using string_view = core::string_view;
|
||||
using request_t = http::request<http::string_body>;
|
||||
struct connection;
|
||||
using handler = std::function<void(connection&, urls::matches)>;
|
||||
|
||||
int
|
||||
serve(
|
||||
urls::router<handler> const& r,
|
||||
asio::ip::address const& a,
|
||||
unsigned short port,
|
||||
std::string const& doc_root);
|
||||
|
||||
struct connection
|
||||
{
|
||||
connection(asio::io_context& ioc)
|
||||
: socket(ioc) {}
|
||||
|
||||
void
|
||||
string_reply(core::string_view msg);
|
||||
|
||||
void
|
||||
file_reply(core::string_view path);
|
||||
|
||||
void
|
||||
error_reply(http::status, core::string_view msg);
|
||||
|
||||
beast::error_code ec;
|
||||
asio::ip::tcp::socket socket;
|
||||
std::string doc_root;
|
||||
request_t req;
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
/*
|
||||
* Parse cmd-line params
|
||||
*/
|
||||
if (argc != 4)
|
||||
{
|
||||
core::string_view exec = argv[0];
|
||||
auto file_pos = exec.find_last_of("/\\");
|
||||
if (file_pos != core::string_view::npos)
|
||||
exec = exec.substr(file_pos + 1);
|
||||
std::cerr
|
||||
<< "Usage: " << exec
|
||||
<< " <address> <port> <doc_root>\n"
|
||||
"Example: " << exec << " 0.0.0.0 8080 .\n"
|
||||
"Default values:\n"
|
||||
"- address: 0.0.0.0\n"
|
||||
"- port: 8080\n"
|
||||
"- doc_root: ./\n";
|
||||
}
|
||||
auto const address = asio::ip::make_address(argc > 1 ? argv[1] : "0.0.0.0");
|
||||
auto const port = static_cast<unsigned short>(argc > 2 ? std::atoi(argv[2]) : 8080);
|
||||
auto const doc_root = std::string(argc > 3 ? argv[3] : ".");
|
||||
|
||||
/*
|
||||
* Create router
|
||||
*/
|
||||
urls::router<handler> r;
|
||||
|
||||
r.insert("/", [&](connection& c, urls::matches const&) {
|
||||
c.string_reply("Hello!");
|
||||
});
|
||||
|
||||
r.insert("/user/{name}", [&](connection& c, urls::matches const& m) {
|
||||
std::string msg = "Hello, ";
|
||||
urls::pct_string_view(m[0]).decode({}, urls::string_token::append_to(msg));
|
||||
msg += "!";
|
||||
c.string_reply(msg);
|
||||
});
|
||||
|
||||
r.insert("/user", [&](connection& c, urls::matches const&) {
|
||||
std::string msg = "Users: ";
|
||||
auto names = {"johndoe", "maria", "alice"};
|
||||
for (auto name: names) {
|
||||
msg += "<a href=\"/user/";
|
||||
msg += name;
|
||||
msg += "\">";
|
||||
msg += name;
|
||||
msg += "</a> ";
|
||||
}
|
||||
c.string_reply(msg);
|
||||
});
|
||||
|
||||
r.insert("/public/{path+}", [&](connection& c, urls::matches m) {
|
||||
c.file_reply(m["path"]);
|
||||
});
|
||||
|
||||
return serve(r, address, port, doc_root);
|
||||
}
|
||||
|
||||
#define ROUTER_CHECK(cond) if(!(cond)) { break; }
|
||||
#define ROUTER_CHECK_EC(ec, cat) if(ec.failed()) { std::cerr << #cat << ": " << ec.message() << "\n"; break; }
|
||||
|
||||
int
|
||||
serve(
|
||||
urls::router<handler> const& r,
|
||||
asio::ip::address const& address,
|
||||
unsigned short port,
|
||||
std::string const& doc_root)
|
||||
{
|
||||
/*
|
||||
* Serve the routes with a simple synchronous
|
||||
* server. This is an implementation detail
|
||||
* in the context of this example.
|
||||
*/
|
||||
std::cout << "Listening on http://" << address << ":" << port << "\n";
|
||||
asio::io_context ioc(1);
|
||||
asio::ip::tcp::acceptor acceptor(ioc, {address, port});
|
||||
urls::matches m;
|
||||
for(;;)
|
||||
{
|
||||
connection c(ioc);
|
||||
c.doc_root = doc_root;
|
||||
acceptor.accept(c.socket);
|
||||
beast::flat_buffer buffer;
|
||||
for(;;)
|
||||
{
|
||||
// Read a request
|
||||
http::read(c.socket, buffer, c.req, c.ec);
|
||||
ROUTER_CHECK(c.ec != http::error::end_of_stream)
|
||||
ROUTER_CHECK_EC(c.ec, read)
|
||||
// Handle request
|
||||
auto rpath = urls::parse_path(c.req.target());
|
||||
if (c.req.method() != http::verb::get &&
|
||||
c.req.method() != http::verb::head)
|
||||
c.error_reply(
|
||||
http::status::bad_request,
|
||||
std::string("Unknown HTTP-method: ") +
|
||||
std::string(c.req.method_string()));
|
||||
else if (!rpath)
|
||||
c.error_reply(http::status::bad_request, "Illegal request-target");
|
||||
else if (auto h = r.find(*rpath, m))
|
||||
(*h)(c, m);
|
||||
else
|
||||
c.error_reply(
|
||||
http::status::not_found,
|
||||
"The resource '" +
|
||||
std::string(rpath->buffer()) +
|
||||
"' was not found.");
|
||||
ROUTER_CHECK_EC(c.ec, write)
|
||||
ROUTER_CHECK(c.req.keep_alive())
|
||||
}
|
||||
c.socket.shutdown(asio::ip::tcp::socket::shutdown_send, c.ec);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#undef ROUTER_CHECK_EC
|
||||
#undef ROUTER_CHECK
|
||||
|
||||
void
|
||||
connection::
|
||||
error_reply(http::status s, core::string_view msg)
|
||||
{
|
||||
// invalid route
|
||||
http::response<http::string_body> res{s, req.version()};
|
||||
res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
|
||||
res.set(http::field::content_type, "text/html");
|
||||
res.keep_alive(req.keep_alive());
|
||||
res.body() = msg;
|
||||
res.prepare_payload();
|
||||
http::write(socket, res, ec);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
connection::
|
||||
string_reply(core::string_view msg)
|
||||
{
|
||||
http::response<http::string_body> res{http::status::ok, req.version()};
|
||||
res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
|
||||
res.set(http::field::content_type, "text/html");
|
||||
res.keep_alive(req.keep_alive());
|
||||
res.body() = msg;
|
||||
res.prepare_payload();
|
||||
http::write(socket, res, ec);
|
||||
}
|
||||
|
||||
core::string_view
|
||||
mime_type(core::string_view path);
|
||||
|
||||
std::string
|
||||
path_cat(
|
||||
beast::string_view base,
|
||||
beast::string_view path);
|
||||
|
||||
void
|
||||
connection::
|
||||
file_reply(core::string_view path)
|
||||
{
|
||||
http::file_body::value_type body;
|
||||
std::string jpath = path_cat(doc_root, path);
|
||||
body.open(jpath.c_str(), beast::file_mode::scan, ec);
|
||||
if(ec == beast::errc::no_such_file_or_directory)
|
||||
{
|
||||
error_reply(
|
||||
http::status::not_found,
|
||||
"The resource '" + std::string(path) +
|
||||
"' was not found in " + jpath);
|
||||
return;
|
||||
}
|
||||
auto const size = body.size();
|
||||
http::response<http::file_body> res{
|
||||
std::piecewise_construct,
|
||||
std::make_tuple(std::move(body)),
|
||||
std::make_tuple(http::status::ok, req.version())};
|
||||
res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
|
||||
res.set(http::field::content_type, mime_type(path));
|
||||
res.content_length(size);
|
||||
res.keep_alive(req.keep_alive());
|
||||
http::write(socket, res, ec);
|
||||
}
|
||||
|
||||
// Append an HTTP rel-path to a local filesystem path.
|
||||
// The returned path is normalized for the platform.
|
||||
std::string
|
||||
path_cat(
|
||||
core::string_view base,
|
||||
core::string_view path)
|
||||
{
|
||||
if (base.empty())
|
||||
return std::string(path);
|
||||
std::string result(base);
|
||||
#ifdef BOOST_MSVC
|
||||
char constexpr path_separator = '\\';
|
||||
#else
|
||||
char constexpr path_separator = '/';
|
||||
#endif
|
||||
if( result.back() == path_separator &&
|
||||
path.starts_with(path_separator))
|
||||
result.resize(result.size() - 1);
|
||||
else if (result.back() != path_separator &&
|
||||
!path.starts_with(path_separator))
|
||||
{
|
||||
result.push_back(path_separator);
|
||||
}
|
||||
result.append(path.data(), path.size());
|
||||
#ifdef BOOST_MSVC
|
||||
for(auto& c : result)
|
||||
if(c == '/')
|
||||
c = path_separator;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
core::string_view
|
||||
mime_type(core::string_view path)
|
||||
{
|
||||
using beast::iequals;
|
||||
auto const ext = [&path]
|
||||
{
|
||||
auto const pos = path.rfind(".");
|
||||
if(pos == beast::string_view::npos)
|
||||
return beast::string_view{};
|
||||
return path.substr(pos);
|
||||
}();
|
||||
if(iequals(ext, ".htm")) return "text/html";
|
||||
if(iequals(ext, ".html")) return "text/html";
|
||||
if(iequals(ext, ".php")) return "text/html";
|
||||
if(iequals(ext, ".css")) return "text/css";
|
||||
if(iequals(ext, ".txt")) return "text/plain";
|
||||
if(iequals(ext, ".js")) return "application/javascript";
|
||||
if(iequals(ext, ".json")) return "application/json";
|
||||
if(iequals(ext, ".xml")) return "application/xml";
|
||||
if(iequals(ext, ".swf")) return "application/x-shockwave-flash";
|
||||
if(iequals(ext, ".flv")) return "video/x-flv";
|
||||
if(iequals(ext, ".png")) return "image/png";
|
||||
if(iequals(ext, ".jpe")) return "image/jpeg";
|
||||
if(iequals(ext, ".jpeg")) return "image/jpeg";
|
||||
if(iequals(ext, ".jpg")) return "image/jpeg";
|
||||
if(iequals(ext, ".gif")) return "image/gif";
|
||||
if(iequals(ext, ".bmp")) return "image/bmp";
|
||||
if(iequals(ext, ".ico")) return "image/vnd.microsoft.icon";
|
||||
if(iequals(ext, ".tiff")) return "image/tiff";
|
||||
if(iequals(ext, ".tif")) return "image/tiff";
|
||||
if(iequals(ext, ".svg")) return "image/svg+xml";
|
||||
if(iequals(ext, ".svgz")) return "image/svg+xml";
|
||||
return "application/text";
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
|
||||
471
doc/modules/ROOT/pages/examples/sanitize.adoc
Normal file
471
doc/modules/ROOT/pages/examples/sanitize.adoc
Normal file
@@ -0,0 +1,471 @@
|
||||
//
|
||||
// Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/url
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
= Sanitizing URLs
|
||||
|
||||
This example parses a non-strict or invalid URL
|
||||
into path components according to its delimiters.
|
||||
This pattern can be adapted to the requirements of other
|
||||
applications.
|
||||
|
||||
Once the non-strict components are determined, a new URL is
|
||||
created and its parts are set with the `set_encoded_X`
|
||||
functions, which will encode any invalid chars accordingly.
|
||||
|
||||
This sort of transformation is useful in applications that are
|
||||
extremely loose in what kinds of URLs they accept, such as
|
||||
browsers. The sanitized URL can later be used for machine-to-machine
|
||||
communication.
|
||||
|
||||
Using non-strict URLs directly is a security concern in
|
||||
machine-to-machine communication, is ambiguous, and also
|
||||
involve an extra cost for the transformations.
|
||||
|
||||
Different transformations are required by different applications to
|
||||
construct a valid URL appropriate for machine-to-machine communication.
|
||||
For instance, if an invalid relative reference includes something that
|
||||
looks like a host in the first path segment, browsers usually interpret
|
||||
that as the host with an implicit "https" scheme. Other applications
|
||||
also have other implicit schemes.
|
||||
|
||||
The example also identifies whether the input url is already valid.
|
||||
It includes diagnostics that can be used to help the user determine
|
||||
if a URL is invalid and why it's invalid.
|
||||
|
||||
Once all transformations are applied, the result is a URL
|
||||
appropriate for machine-to-machine communication.
|
||||
|
||||
// example_sanitize_url
|
||||
[source,cpp]
|
||||
----
|
||||
|
||||
/*
|
||||
This example parses a non-strict / invalid URL
|
||||
into path components according to its delimiters.
|
||||
This pattern can be adapted to the requirements of other
|
||||
applications.
|
||||
|
||||
Once the non-strict components are determined, a new URL is
|
||||
created and its parts are set with the set_encoded_X
|
||||
functions, which will encode any invalid chars accordingly.
|
||||
|
||||
This sort of transformation is useful in applications that are
|
||||
extremely loose in what kinds of URLs they accept, such as
|
||||
browsers. The sanitized URL can later be used for machine-to-machine
|
||||
communication.
|
||||
|
||||
Using non-strict URLs directly is a security concern in
|
||||
machine-to-machine communication, is ambiguous, and also
|
||||
involve an extra cost for the transformations.
|
||||
|
||||
Different transformations are required by different applications to
|
||||
construct a valid URL appropriate for machine-to-machine communication.
|
||||
For instance, if an invalid relative reference includes something that
|
||||
looks like a host in the first path segment, browsers usually interpret
|
||||
that as the host with an implicit "https" scheme. Other applications
|
||||
also have other implicit schemes.
|
||||
|
||||
The example also identifies whether the input url is already valid.
|
||||
It includes diagnostics that can be used to help the user determine
|
||||
if a URL is invalid and why it's invalid.
|
||||
|
||||
Once all transformations are applied, the result is a URL
|
||||
appropriate for machine-to-machine communication.
|
||||
*/
|
||||
|
||||
#include <boost/url/url.hpp>
|
||||
#include <boost/url/parse.hpp>
|
||||
#include <boost/url/parse_path.hpp>
|
||||
#include <boost/url/string_view.hpp>
|
||||
#include <boost/url/grammar/alpha_chars.hpp>
|
||||
#include <boost/url/grammar/charset.hpp>
|
||||
#include <boost/url/grammar/digit_chars.hpp>
|
||||
#include <boost/url/grammar/lut_chars.hpp>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
|
||||
namespace urls = boost::urls;
|
||||
namespace core = boost::core;
|
||||
|
||||
struct url_components
|
||||
{
|
||||
core::string_view scheme;
|
||||
core::string_view user;
|
||||
core::string_view password;
|
||||
core::string_view hostname;
|
||||
core::string_view port;
|
||||
core::string_view path;
|
||||
core::string_view query;
|
||||
core::string_view fragment;
|
||||
};
|
||||
|
||||
core::string_view
|
||||
port_of_scheme(core::string_view scheme_str) {
|
||||
static std::array<std::pair<core::string_view, core::string_view>, 21> scheme_ports =
|
||||
{{
|
||||
{"http", "80"},
|
||||
{"ftp", "21"},
|
||||
{"https", "443"},
|
||||
{"gopher", "70"},
|
||||
{"ldap", "389"},
|
||||
{"nntp", "119"},
|
||||
{"snews", "563"},
|
||||
{"imap", "143"},
|
||||
{"pop", "110"},
|
||||
{"sip", "5060"},
|
||||
{"rtsp", "554"},
|
||||
{"wais", "210"},
|
||||
{"z39.50r", "210"},
|
||||
{"z39.50s", "210"},
|
||||
{"prospero", "191"},
|
||||
{"nfs", "2049"},
|
||||
{"tip", "3372"},
|
||||
{"acap", "674"},
|
||||
{"telnet", "23"},
|
||||
{"ssh", "22"},
|
||||
{"", "65535"}
|
||||
}};
|
||||
|
||||
auto iequals = [](core::string_view a, core::string_view b)
|
||||
{
|
||||
if (b.size() != a.size()) {
|
||||
return false;
|
||||
}
|
||||
for (unsigned int i = 0; i < a.size(); ++i) {
|
||||
if (std::tolower(a[i]) != std::tolower(b[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto const& it = std::find_if(
|
||||
scheme_ports.begin(),
|
||||
scheme_ports.end(),
|
||||
[&](std::pair<core::string_view, core::string_view> const& s) {
|
||||
return iequals(s.first, scheme_str);
|
||||
});
|
||||
|
||||
if (it != scheme_ports.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
extract_relative_ref(
|
||||
core::string_view hostinfo_relative,
|
||||
url_components &out)
|
||||
{
|
||||
// split path and query#fragment
|
||||
constexpr urls::grammar::lut_chars path_end_chars("?#\0");
|
||||
auto it = urls::grammar::find_if(
|
||||
hostinfo_relative.begin(),
|
||||
hostinfo_relative.end(), path_end_chars);
|
||||
core::string_view query_and_frag = hostinfo_relative.substr(it - hostinfo_relative.begin());
|
||||
if (query_and_frag != hostinfo_relative)
|
||||
out.path = hostinfo_relative.substr(
|
||||
0, query_and_frag.data() - hostinfo_relative.data());
|
||||
if (query_and_frag.empty())
|
||||
return;
|
||||
|
||||
// ?query#fragment
|
||||
if (query_and_frag.front() == '?') {
|
||||
query_and_frag = query_and_frag.substr(1);
|
||||
core::string_view::size_type hash_pos = query_and_frag.find('#');
|
||||
if (hash_pos != core::string_view::npos) {
|
||||
core::string_view fragment_part = query_and_frag.substr(hash_pos);
|
||||
out.fragment = fragment_part.substr(1);
|
||||
out.query = query_and_frag.substr(
|
||||
0, fragment_part.data() - query_and_frag.data());
|
||||
} else {
|
||||
out.query = query_and_frag;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// fragment
|
||||
out.fragment = query_and_frag.substr(1);
|
||||
}
|
||||
|
||||
void
|
||||
extract_userinfo_relative(
|
||||
core::string_view relative_ref,
|
||||
core::string_view userinfo_relative,
|
||||
core::string_view host_info,
|
||||
url_components& out) {
|
||||
// We expect userinfo_relative to point to the first character of
|
||||
// the hostname. If there's a port it is the first colon,
|
||||
// except with IPv6.
|
||||
auto host_end_pos = host_info.find(':');
|
||||
if (host_end_pos == core::string_view::npos)
|
||||
{
|
||||
// definitely no port
|
||||
out.hostname = userinfo_relative.substr(
|
||||
0, relative_ref.data() - userinfo_relative.data());
|
||||
return extract_relative_ref(relative_ref, out);
|
||||
}
|
||||
|
||||
// extract hostname and port
|
||||
out.hostname = userinfo_relative.substr(0, host_end_pos);
|
||||
core::string_view host_relative = userinfo_relative.substr(host_end_pos + 1);
|
||||
out.port = host_relative.substr(0, relative_ref.data() - host_relative.data());
|
||||
|
||||
// validate port
|
||||
bool const valid_port =
|
||||
urls::grammar::find_if_not(
|
||||
out.port.begin(),
|
||||
out.port.end(),
|
||||
urls::grammar::digit_chars)
|
||||
== out.port.end();
|
||||
if (!valid_port)
|
||||
{
|
||||
// move port to hostname where it can be encoded
|
||||
out.hostname = {out.hostname.begin(), out.port.end()};
|
||||
out.port = {};
|
||||
}
|
||||
|
||||
extract_relative_ref(relative_ref, out);
|
||||
if (out.port.empty() && !out.scheme.empty())
|
||||
out.port = port_of_scheme(out.scheme);
|
||||
}
|
||||
|
||||
void
|
||||
extract_scheme_relative(
|
||||
core::string_view scheme_relative,
|
||||
url_components &out)
|
||||
{
|
||||
// hostinfo
|
||||
constexpr urls::grammar::lut_chars hostinfo_end_chars("/?#\0");
|
||||
auto it = urls::grammar::find_if(
|
||||
scheme_relative.begin(),
|
||||
scheme_relative.end(),
|
||||
hostinfo_end_chars);
|
||||
auto path_offset = (std::min)(
|
||||
scheme_relative.size(),
|
||||
static_cast<std::size_t>(it - scheme_relative.begin()));
|
||||
core::string_view host_info = scheme_relative.substr(0, path_offset);
|
||||
|
||||
// userinfo
|
||||
core::string_view relative_ref = scheme_relative.substr(path_offset);
|
||||
auto host_offset = host_info.find_last_of('@');
|
||||
if (host_offset == core::string_view::npos)
|
||||
return extract_userinfo_relative(
|
||||
relative_ref,
|
||||
scheme_relative,
|
||||
host_info,
|
||||
out);
|
||||
|
||||
// password
|
||||
core::string_view userinfo_at_relative = scheme_relative.substr(host_offset);
|
||||
core::string_view userinfo(host_info.data(), userinfo_at_relative.data() - host_info.data());
|
||||
auto password_offset = std::min(userinfo.size(), userinfo.find(':'));
|
||||
if (password_offset != userinfo.size()) {
|
||||
out.user = scheme_relative.substr(0, password_offset);
|
||||
core::string_view password = scheme_relative.substr(password_offset + 1);
|
||||
out.password = password.substr(0, userinfo_at_relative.data() - password.data());
|
||||
} else {
|
||||
out.user = scheme_relative.substr(0, userinfo_at_relative.data() - scheme_relative.data());
|
||||
}
|
||||
|
||||
// userinfo-relative
|
||||
core::string_view userinfo_relative = userinfo_at_relative.substr(1);
|
||||
it = urls::grammar::find_if(
|
||||
userinfo_relative.begin(),
|
||||
userinfo_relative.end(),
|
||||
hostinfo_end_chars);
|
||||
path_offset = (std::min)(
|
||||
userinfo_relative.size(),
|
||||
static_cast<std::size_t>(it - userinfo_relative.begin()));
|
||||
host_info = userinfo_relative.substr(0, path_offset);
|
||||
extract_userinfo_relative(
|
||||
relative_ref,
|
||||
userinfo_relative,
|
||||
host_info,
|
||||
out);
|
||||
}
|
||||
|
||||
void
|
||||
extract_uri_components(
|
||||
core::string_view s,
|
||||
url_components &out)
|
||||
{
|
||||
if (s.starts_with("//") && !s.starts_with("///"))
|
||||
return extract_scheme_relative(s.substr(2), out);
|
||||
|
||||
if (s.starts_with('/'))
|
||||
return extract_relative_ref(s, out);
|
||||
|
||||
// extract scheme
|
||||
// first char in a scheme must be letter (we accept uppercase here)
|
||||
bool has_scheme = false;
|
||||
if (!s.empty() && urls::grammar::alpha_chars(s.front())) {
|
||||
constexpr
|
||||
urls::grammar::lut_chars scheme_chars(
|
||||
"0123456789+-.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
||||
char const* it = urls::grammar::find_if_not(
|
||||
s.begin() + 1, s.end(), scheme_chars);
|
||||
size_t scheme_size = (std::min)(
|
||||
s.size(), static_cast<std::size_t>(it - s.begin()));
|
||||
// scheme must be non-empty and followed by ':'
|
||||
if (s.size() > scheme_size && s[scheme_size] == ':') {
|
||||
out.scheme = s.substr(0, scheme_size);
|
||||
has_scheme = true;
|
||||
}
|
||||
}
|
||||
|
||||
// The usual route, parse scheme first
|
||||
core::string_view scheme_relative = s;
|
||||
if (has_scheme)
|
||||
scheme_relative = s.substr(out.scheme.size() + 1);
|
||||
|
||||
const bool has_authority = scheme_relative.starts_with("//");
|
||||
const bool is_relative_ref = !has_scheme && !has_authority;
|
||||
if (is_relative_ref)
|
||||
{
|
||||
// this is the trick browsers usually apply when 1) there's no
|
||||
// authority because the "//" is missing, 2) the scheme is also missing,
|
||||
// and 3) the first path segment looks like an authority
|
||||
//
|
||||
// This behavior is widespread, although it's ambiguous because valid
|
||||
// host characters are also valid path characters.
|
||||
//
|
||||
// It's this rule that allows for things like "www.boost.org" in the
|
||||
// browser. This is an invalid URL because it has no "//" to indicate
|
||||
// this is the authority and "www.boost.org" is a perfectly valid
|
||||
// path segment.
|
||||
auto first_seg_offset = (std::min)(s.size(), s.find_first_of('/'));
|
||||
core::string_view first_seg = s.substr(0, first_seg_offset);
|
||||
auto host_delimiter_pos = first_seg.find_first_of(".:");
|
||||
bool const looks_like_authority =
|
||||
urls::parse_authority(first_seg) &&
|
||||
host_delimiter_pos != core::string_view::npos &&
|
||||
host_delimiter_pos != first_seg.size() - 1;
|
||||
if (looks_like_authority)
|
||||
return extract_scheme_relative(s, out);
|
||||
|
||||
// if the first_seg is really a seg, parse as relative ref
|
||||
return extract_relative_ref(s, out);
|
||||
}
|
||||
|
||||
if (has_authority)
|
||||
scheme_relative = scheme_relative.substr(2);
|
||||
|
||||
// all that's left is a relative path
|
||||
return extract_relative_ref(scheme_relative, out);
|
||||
}
|
||||
|
||||
void
|
||||
sanitize_uri(core::string_view s, urls::url_base& dest) {
|
||||
url_components o;
|
||||
dest.clear();
|
||||
extract_uri_components(s, o);
|
||||
if (o.scheme.data())
|
||||
dest.set_scheme(o.scheme);
|
||||
if (o.user.data())
|
||||
dest.set_encoded_user(o.user);
|
||||
if (o.password.data())
|
||||
dest.set_encoded_password(o.password);
|
||||
if (o.hostname.data())
|
||||
dest.set_encoded_host(o.hostname);
|
||||
if (o.port.data())
|
||||
dest.set_port(o.port);
|
||||
if (o.path.data())
|
||||
dest.set_encoded_path(o.path);
|
||||
if (o.query.data())
|
||||
dest.set_encoded_query(o.query);
|
||||
if (o.fragment.data())
|
||||
dest.set_encoded_fragment(o.fragment);
|
||||
}
|
||||
|
||||
urls::url
|
||||
sanitize_uri(core::string_view s) {
|
||||
urls::url u;
|
||||
sanitize_uri(s, u);
|
||||
return u;
|
||||
}
|
||||
|
||||
void
|
||||
print_url_components(urls::url_view u)
|
||||
{
|
||||
std::cout << "url: " << u.buffer() << '\n';
|
||||
if (u.has_scheme())
|
||||
std::cout << "scheme: " << u.scheme() << '\n';
|
||||
if (u.has_userinfo())
|
||||
std::cout << "user: " << u.encoded_user() << '\n';
|
||||
if (u.has_password())
|
||||
std::cout << "password: " << u.encoded_password() << '\n';
|
||||
if (u.has_authority())
|
||||
std::cout << "hostname: " << u.encoded_host() << '\n';
|
||||
if (u.has_port())
|
||||
std::cout << "port: " << u.port() << '\n';
|
||||
std::cout << "path: " << u.encoded_path() << '\n';
|
||||
std::cout << "segments:\n";
|
||||
for (auto seg: u.encoded_segments())
|
||||
std::cout << "- " << seg << '\n';
|
||||
if (u.has_query())
|
||||
std::cout << "query: " << u.encoded_query() << '\n';
|
||||
std::cout << "params:\n";
|
||||
for (auto param: u.encoded_params())
|
||||
{
|
||||
if (param.has_value)
|
||||
std::cout << "- " << param.key << ": " << param.value << '\n';
|
||||
else
|
||||
std::cout << "- " << param.key << '\n';
|
||||
}
|
||||
if (u.has_fragment())
|
||||
std::cout << "fragment: " << u.encoded_fragment() << '\n';
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
core::string_view exec = argv[0];
|
||||
auto p = exec.find_last_of("/\\");
|
||||
if (p != core::string_view::npos)
|
||||
exec = exec.substr(p);
|
||||
std::cerr
|
||||
<< "Usage: " << exec
|
||||
<< " <url>\n"
|
||||
"target: a non-strict url\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
core::string_view uri_str = argv[1];
|
||||
|
||||
boost::system::result<urls::url_view> ru = urls::parse_uri_reference(uri_str);
|
||||
if (ru)
|
||||
{
|
||||
urls::url_view u = *ru;
|
||||
if (u.has_scheme() && u.has_fragment())
|
||||
std::cout << "Input is a valid URL\n";
|
||||
else if (u.has_scheme())
|
||||
std::cout << "Input is a valid absolute URL\n";
|
||||
else
|
||||
std::cout << "Input is a valid relative URL\n";
|
||||
print_url_components(u);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
std::cout << "Sanitizing URL:\n";
|
||||
std::cout << "input: " << uri_str << '\n';
|
||||
urls::url u = sanitize_uri(uri_str);
|
||||
print_url_components(u);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
//
|
||||
|
||||
|
||||
== Character Sets
|
||||
= Character Sets
|
||||
|
||||
A __character__ represents a subset of low-ASCII characters,
|
||||
A __character set__ represents a subset of low-ASCII characters,
|
||||
used as a building block for constructing rules. The library
|
||||
models them as callable predicates invocable with this
|
||||
equivalent signature:
|
||||
@@ -22,14 +22,20 @@ bool( char ch ) const noexcept;
|
||||
----
|
||||
|
||||
|
||||
The `CharSet` concept describes the requirements on
|
||||
The __CharSet__ concept describes the requirements on
|
||||
syntax and semantics for these types. Here we declare
|
||||
a character set type that includes the horizontal and
|
||||
vertical whitespace characters:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_2_2
|
||||
struct ws_chars_t
|
||||
{
|
||||
constexpr bool operator()( char c ) const noexcept
|
||||
{
|
||||
return c == '\t' || c == ' ' || c == '\r' || c == '\n';
|
||||
}
|
||||
};
|
||||
----
|
||||
|
||||
|
||||
@@ -38,7 +44,7 @@ the requirements:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_2_3
|
||||
static_assert( is_charset< ws_chars_t >::value, "CharSet requirements not met" );
|
||||
----
|
||||
|
||||
|
||||
@@ -49,7 +55,7 @@ abstraction:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_2_4
|
||||
constexpr ws_chars_t ws_chars{};
|
||||
----
|
||||
|
||||
|
||||
@@ -65,50 +71,73 @@ character:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_2_5
|
||||
core::string_view get_token( core::string_view s ) noexcept
|
||||
{
|
||||
auto it0 = s.data();
|
||||
auto const end = it0 + s.size();
|
||||
|
||||
// find the first non-whitespace character
|
||||
it0 = find_if_not( it0, end, ws_chars );
|
||||
|
||||
if( it0 == end )
|
||||
{
|
||||
// all whitespace or empty string
|
||||
return {};
|
||||
}
|
||||
|
||||
// find the next whitespace character
|
||||
auto it1 = find_if( it0, end, ws_chars );
|
||||
|
||||
// [it0, it1) is the part we want
|
||||
return core::string_view( it0, it1 - it0 );
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
The function can now be called thusly:
|
||||
|
||||
// code_grammar_2_6
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_2_6
|
||||
assert( get_token( " \t john-doe\r\n \t jane-doe\r\n") == "john-doe" );
|
||||
----
|
||||
|
||||
|
||||
The library provides these often-used character sets:
|
||||
|
||||
// [table Character Sets [
|
||||
// [Value]
|
||||
// [Description]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__grammar__alnum_chars `alnum_chars`]]
|
||||
// [
|
||||
// Contains the uppercase and lowercase letters, and digits.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__grammar__alpha_chars `alpha_chars`]]
|
||||
// [
|
||||
// Contains the uppercase and lowercase letters.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__grammar__digit_chars `digit_chars`]]
|
||||
// [
|
||||
// Contains the decimal digit characters.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__grammar__hexdig_chars `hexdig_chars`]]
|
||||
// [
|
||||
// Contains the uppercase and lowercase hexadecimal
|
||||
// digit characters.
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__grammar__vchars `vchars`]]
|
||||
// [
|
||||
// Contains the visible characters (i.e. non whitespace).
|
||||
// ]
|
||||
// ]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Value|Description
|
||||
|
||||
// Row 1, Column 1
|
||||
|`alnum_chars`
|
||||
// Row 1, Column 2
|
||||
|Contains the uppercase and lowercase letters, and digits.
|
||||
|
||||
// Row 2, Column 1
|
||||
|`alpha_chars`
|
||||
// Row 2, Column 2
|
||||
|Contains the uppercase and lowercase letters.
|
||||
|
||||
// Row 3, Column 1
|
||||
|`digit_chars`
|
||||
// Row 3, Column 2
|
||||
|Contains the decimal digit characters.
|
||||
|
||||
// Row 4, Column 1
|
||||
|`hexdig_chars`
|
||||
// Row 4, Column 2
|
||||
|Contains the uppercase and lowercase hexadecimal
|
||||
digit characters.
|
||||
|
||||
// Row 5, Column 1
|
||||
|`vchars`
|
||||
// Row 5, Column 2
|
||||
|Contains the visible characters (i.e. non whitespace).
|
||||
|
||||
|===
|
||||
|
||||
|
||||
|
||||
Some of the character sets in the library have implementations
|
||||
@@ -119,18 +148,19 @@ using Streaming SIMD Extensions 2
|
||||
(https://en.wikipedia.org/wiki/SSE2[SSE2,window=blank_]),
|
||||
available on all x86 and x64 architectures.
|
||||
|
||||
=== The lut_chars Type
|
||||
== The lut_chars Type
|
||||
|
||||
The `lut_chars` type satisfies the `CharSet`
|
||||
The `lut_chars` type satisfies the __CharSet__
|
||||
requirements and offers an optimized `constexpr`
|
||||
implementation which provides enhanced performance
|
||||
and notational convenience for specifying character
|
||||
sets. Compile-time instances can be constructed
|
||||
from strings:
|
||||
|
||||
// code_grammar_2_7
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_2_7
|
||||
constexpr lut_chars vowels = "AEIOU" "aeiou";
|
||||
----
|
||||
|
||||
|
||||
@@ -138,9 +168,10 @@ We can use `operator+` and `operator-` notation to add and
|
||||
remove elements from the set at compile time. For example,
|
||||
sometimes the character 'y' sounds like a vowel:
|
||||
|
||||
// code_grammar_2_8
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_2_8
|
||||
constexpr auto vowels_and_y = vowels + 'y' + 'Y';
|
||||
----
|
||||
|
||||
|
||||
@@ -151,7 +182,14 @@ Here we create the set of visible characters using a lambda:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_2_9
|
||||
struct is_visible
|
||||
{
|
||||
constexpr bool operator()( char ch ) const noexcept
|
||||
{
|
||||
return ch >= 33 && ch <= 126;
|
||||
}
|
||||
};
|
||||
constexpr lut_chars visible_chars( is_visible{} ); // (since C++11)
|
||||
----
|
||||
|
||||
|
||||
@@ -159,23 +197,25 @@ Alternatively:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_2_10
|
||||
constexpr lut_chars visible_chars( [](char ch) { return ch >= 33 && ch <= 126; } ); // (since C++17)
|
||||
----
|
||||
|
||||
|
||||
Differences can be calculated with `operator-`:
|
||||
|
||||
// code_grammar_2_11
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_2_11
|
||||
constexpr auto visible_non_vowels = visible_chars - vowels;
|
||||
----
|
||||
|
||||
|
||||
We can also remove individual characters:
|
||||
|
||||
// code_grammar_2_12
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_2_12
|
||||
constexpr auto visible_non_vowels_or_y = visible_chars - vowels - 'y';
|
||||
----
|
||||
|
||||
|
||||
|
||||
@@ -8,21 +8,21 @@
|
||||
//
|
||||
|
||||
|
||||
== Compound Rules
|
||||
= Compound Rules
|
||||
|
||||
The rules shown so far have defined
|
||||
https://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols[__terminal__,window=blank_],
|
||||
https://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols[__terminal symbols__,window=blank_],
|
||||
representing indivisible units of grammar. To parse more
|
||||
complex things, a
|
||||
https://en.wikipedia.org/wiki/Parser_combinator[__parser__,window=blank_]
|
||||
(or __compound__) is a rule which accepts as parameters one
|
||||
https://en.wikipedia.org/wiki/Parser_combinator[__parser combinator__,window=blank_]
|
||||
(or __compound rule__) is a rule which accepts as parameters one
|
||||
or more rules and combines them to form a higher order algorithm.
|
||||
In this section we introduce the compound rules provided by the
|
||||
library, and how they may be used to express more complex grammars.
|
||||
|
||||
|
||||
|
||||
=== Tuple Rule
|
||||
== Tuple Rule
|
||||
|
||||
Consider the following grammar:
|
||||
|
||||
@@ -37,9 +37,10 @@ or more specified rules in sequence. The folllowing defines
|
||||
a sequence using some character literals and two decimal octets,
|
||||
which is a fancy way of saying a number between 0 and 255:
|
||||
|
||||
// code_grammar_3_1
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_3_1
|
||||
constexpr auto version_rule = tuple_rule( delim_rule( 'v' ), dec_octet_rule, delim_rule( '.' ), dec_octet_rule );
|
||||
----
|
||||
|
||||
|
||||
@@ -48,22 +49,26 @@ to the value type of each rule specified upon construction. The decimal
|
||||
octets are represented by the `dec_octet_rule` which stores its
|
||||
result in an `unsigned char`:
|
||||
|
||||
// code_grammar_3_2
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_3_2
|
||||
system::result< std::tuple< core::string_view, unsigned char, core::string_view, unsigned char > > rv = parse( "v42.44800", version_rule );
|
||||
----
|
||||
|
||||
|
||||
To extract elements from `std::tuple` the function `std::get`
|
||||
To extract elements from `std::tuple` the function https://en.cppreference.com/w/cpp/utility/tuple/get[`std::get`,window=blank_]
|
||||
must be used. In this case, we don't care to know the value for
|
||||
the matching character literals. The `tuple_rule` discards match
|
||||
results whose value type is `void`. We can use the `squelch`
|
||||
compound rule to convert a matching value type to `void`, and
|
||||
reformulate our rule:
|
||||
|
||||
// code_grammar_3_3
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_3_3
|
||||
constexpr auto version_rule = tuple_rule( squelch( delim_rule( 'v' ) ), dec_octet_rule, squelch( delim_rule( '.' ) ), dec_octet_rule );
|
||||
|
||||
system::result< std::tuple< unsigned char, unsigned char > > rv = parse( "v42.44800", version_rule );
|
||||
----
|
||||
|
||||
|
||||
@@ -71,33 +76,61 @@ When all but one of the value types is `void`, the `std::tuple` is
|
||||
elided and the remaining value type is promoted to the result of
|
||||
the match:
|
||||
|
||||
// code_grammar_3_4
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_3_4
|
||||
// port = ":" unsigned-short
|
||||
|
||||
constexpr auto port_rule = tuple_rule( squelch( delim_rule( ':' ) ), unsigned_rule< unsigned short >{} );
|
||||
|
||||
system::result< unsigned short > rv = parse( ":443", port_rule );
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
||||
=== Optional Rule
|
||||
== Optional Rule
|
||||
|
||||
BNF elements in brackets denote optional components. These are
|
||||
expressed using `optional_rule`, whose value type is an
|
||||
`optional`. For example, we can adapt the port rule from
|
||||
above to be an optional component:
|
||||
|
||||
// code_grammar_3_5
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_3_5
|
||||
// port = [ ":" unsigned-short ]
|
||||
|
||||
constexpr auto port_rule = optional_rule( tuple_rule( squelch( delim_rule( ':' ) ), unsigned_rule< unsigned short >{} ) );
|
||||
|
||||
system::result< boost::optional< unsigned short > > rv = parse( ":8080", port_rule );
|
||||
|
||||
assert( rv->has_value() && rv->value() == 8080 );
|
||||
----
|
||||
|
||||
|
||||
In this example we build up a rule to represent an
|
||||
endpoint as an IPv4 address with an optional port:
|
||||
|
||||
// code_grammar_3_6
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_3_6
|
||||
// ipv4_address = dec-octet "." dec-octet "." dec-octet "." dec-octet
|
||||
//
|
||||
// port = ":" unsigned-short
|
||||
//
|
||||
// endpoint = ipv4_address [ port ]
|
||||
|
||||
constexpr auto endpoint_rule = tuple_rule(
|
||||
tuple_rule(
|
||||
dec_octet_rule, squelch( delim_rule( '.' ) ),
|
||||
dec_octet_rule, squelch( delim_rule( '.' ) ),
|
||||
dec_octet_rule, squelch( delim_rule( '.' ) ),
|
||||
dec_octet_rule ),
|
||||
optional_rule(
|
||||
tuple_rule(
|
||||
squelch( delim_rule( ':' ) ),
|
||||
unsigned_rule< unsigned short >{} ) ) );
|
||||
----
|
||||
|
||||
|
||||
@@ -105,19 +138,27 @@ This can be simplified; the library provides `ipv4_address_rule`
|
||||
whose result type is `ipv4_address`, offering more utility
|
||||
than representing the address simply as a collection of four numbers:
|
||||
|
||||
// code_grammar_3_7
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_3_7
|
||||
constexpr auto endpoint_rule = tuple_rule(
|
||||
ipv4_address_rule,
|
||||
optional_rule(
|
||||
tuple_rule(
|
||||
squelch( delim_rule( ':' ) ),
|
||||
unsigned_rule< unsigned short >{} ) ) );
|
||||
|
||||
system::result< std::tuple< ipv4_address, boost::optional< unsigned short > > > rv = parse( "192.168.0.1:443", endpoint_rule );
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
||||
=== Variant Rule
|
||||
== Variant Rule
|
||||
|
||||
BNF elements separated by unquoted slashes represent a set
|
||||
of alternatives from which one element may match. We represent
|
||||
them using `variant_rule`, whose value type is a `variant`.
|
||||
them using `variant_rule`, whose value type is a variant.
|
||||
Consider the following HTTP production rule which comes from
|
||||
https://datatracker.ietf.org/doc/html/rfc7230#section-5.3"[rfc7230,window=blank_]:
|
||||
|
||||
@@ -135,9 +176,16 @@ define the rule, using `origin_form_rule`, `absolute_uri_rule`,
|
||||
and `authority_rule` which come with the library, and obtain
|
||||
a result from parsing a string:
|
||||
|
||||
// code_grammar_3_8
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_3_8
|
||||
constexpr auto request_target_rule = variant_rule(
|
||||
origin_form_rule,
|
||||
absolute_uri_rule,
|
||||
authority_rule,
|
||||
delim_rule('*') );
|
||||
|
||||
system::result< variant2::variant< url_view, url_view, authority_view, core::string_view > > rv = parse( "/results.htm?page=4", request_target_rule );
|
||||
----
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
//
|
||||
|
||||
|
||||
// [section:grammar Customization]
|
||||
[#grammar]
|
||||
= Customization
|
||||
|
||||
For a wide range of applications the library's container interfaces
|
||||
are sufficient for URLs using the generic syntax or the well known
|
||||
@@ -17,7 +18,7 @@ to go beyond what the library offers:
|
||||
|
||||
* Create new custom containers for other schemes
|
||||
* Incorporate the parsing of URLs in an enclosing grammar
|
||||
* Parse `rfc3986` elements in non-URL contexts
|
||||
* Parse https://tools.ietf.org/html/rfc3986[rfc3986,window=blank_] elements in non-URL contexts
|
||||
(`authority_view` is an example of this).
|
||||
* Define new ABNF rules used to parse non-URL strings
|
||||
|
||||
@@ -49,22 +50,26 @@ understanding of this notation is necessary to achieve
|
||||
best results for learning how to use the custom parsing
|
||||
features.
|
||||
|
||||
// [note
|
||||
// Code samples and identifiers in this customization
|
||||
// section are written as if the following declarations
|
||||
// are in effect:
|
||||
//
|
||||
// ```
|
||||
// #include <boost/url/grammar.hpp>
|
||||
//
|
||||
// using namespace ::boost::urls::grammar;
|
||||
// ```
|
||||
// ]
|
||||
[NOTE]
|
||||
====
|
||||
Code samples and identifiers in this customization
|
||||
section are written as if the following declarations
|
||||
are in effect:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
#include <boost/url/grammar.hpp>
|
||||
|
||||
using namespace ::boost::urls::grammar;
|
||||
----
|
||||
|
||||
====
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// [include 4.1.rules.qbk]
|
||||
// [include 4.2.charset.qbk]
|
||||
// [include 4.3.combinators.qbk]
|
||||
// [include 4.4.range.qbk]
|
||||
// [include 4.5.rfc3986.qbk]
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//
|
||||
|
||||
|
||||
== Ranges
|
||||
= Ranges
|
||||
|
||||
|
||||
|
||||
@@ -31,9 +31,11 @@ rule allowing for a prescribed number of repetitions of a specified
|
||||
rule. The following rule matches the grammar for __chunk-ext__
|
||||
defined above:
|
||||
|
||||
// code_grammar_4_1
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_4_1
|
||||
constexpr auto chunk_ext_rule = range_rule(
|
||||
tuple_rule( squelch( delim_rule( ';' ) ), token_rule( alnum_chars ) ) );
|
||||
----
|
||||
|
||||
|
||||
@@ -43,9 +45,13 @@ case, the type is `string_view` because the tuple has one unsquelched
|
||||
element, the `token_rule`. The range can be iterated to produce results,
|
||||
without allocating memory for each element. The following code:
|
||||
|
||||
// code_grammar_4_2
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_4_2
|
||||
system::result< range< core::string_view > > rv = parse( ";johndoe;janedoe;end", chunk_ext_rule );
|
||||
|
||||
for( auto s : rv.value() )
|
||||
std::cout << s << "\n";
|
||||
----
|
||||
|
||||
|
||||
@@ -77,17 +83,25 @@ the minimum number of repetitions, or both the minimum and maximum
|
||||
number of repetitions. Since our list may not be empty, the following
|
||||
rule perfectly captures the __token-list__ grammar:
|
||||
|
||||
// code_grammar_4_3
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_4_3
|
||||
constexpr auto token_list_rule = range_rule(
|
||||
token_rule( alnum_chars ),
|
||||
tuple_rule( squelch( delim_rule( ',' ) ), token_rule( alnum_chars ) ),
|
||||
1 );
|
||||
----
|
||||
|
||||
|
||||
The following code:
|
||||
|
||||
// code_grammar_4_4
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_4_4
|
||||
system::result< range< core::string_view > > rv = parse( "johndoe,janedoe,end", token_list_rule );
|
||||
|
||||
for( auto s : rv.value() )
|
||||
std::cout << s << "\n";
|
||||
----
|
||||
|
||||
|
||||
@@ -102,68 +116,71 @@ end
|
||||
|
||||
|
||||
In the next section we discuss the available rules
|
||||
which are specific to `rfc3986`.
|
||||
which are specific to https://tools.ietf.org/html/rfc3986[rfc3986,window=blank_].
|
||||
|
||||
=== More
|
||||
== More
|
||||
|
||||
These are the rules and compound rules provided by the
|
||||
library. For more details please see the corresponding
|
||||
reference sections.
|
||||
|
||||
// [table Grammar Symbols [
|
||||
// [Name]
|
||||
// [Description]
|
||||
// ][
|
||||
// [__dec_octet_rule__]
|
||||
// [
|
||||
// Match an integer from 0 and 255.
|
||||
// ]
|
||||
// ][
|
||||
// [__delim_rule__]
|
||||
// [
|
||||
// Match a character literal.
|
||||
// ]
|
||||
// ][
|
||||
// [__literal_rule__]
|
||||
// [
|
||||
// Match a character string exactly.
|
||||
// ]
|
||||
// ][
|
||||
// [__not_empty_rule__]
|
||||
// [
|
||||
// Make a matching empty string into an error instead.
|
||||
// ]
|
||||
// ][
|
||||
// [__optional_rule__]
|
||||
// [
|
||||
// Ignore a rule if parsing fails, leaving
|
||||
// the input pointer unchanged.
|
||||
// ]
|
||||
// ][
|
||||
// [__range_rule__]
|
||||
// [
|
||||
// Match a repeating number of elements.
|
||||
// ]
|
||||
// ][
|
||||
// [__token_rule__]
|
||||
// [
|
||||
// Match a string of characters from a character set.
|
||||
// ]
|
||||
// ][
|
||||
// [__tuple_rule__]
|
||||
// [
|
||||
// Match a sequence of specified rules, in order.
|
||||
// ]
|
||||
// ][
|
||||
// [__unsigned_rule__]
|
||||
// [
|
||||
// Match an unsigned integer in decimal form.
|
||||
// ]
|
||||
// ][
|
||||
// [__variant_rule__]
|
||||
// [
|
||||
// Match one of a set of alternatives specified by rules.
|
||||
// ]
|
||||
// ]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Name|Description
|
||||
|
||||
// Row 1, Column 1
|
||||
|`dec_octet_rule`
|
||||
// Row 1, Column 2
|
||||
|Match an integer from 0 and 255.
|
||||
|
||||
// Row 2, Column 1
|
||||
|`delim_rule`
|
||||
// Row 2, Column 2
|
||||
|Match a character literal.
|
||||
|
||||
// Row 3, Column 1
|
||||
|`literal_rule`
|
||||
// Row 3, Column 2
|
||||
|Match a character string exactly.
|
||||
|
||||
// Row 4, Column 1
|
||||
|`not_empty_rule`
|
||||
// Row 4, Column 2
|
||||
|Make a matching empty string into an error instead.
|
||||
|
||||
// Row 5, Column 1
|
||||
|`optional_rule`
|
||||
// Row 5, Column 2
|
||||
|Ignore a rule if parsing fails, leaving
|
||||
the input pointer unchanged.
|
||||
|
||||
// Row 6, Column 1
|
||||
|`range_rule`
|
||||
// Row 6, Column 2
|
||||
|Match a repeating number of elements.
|
||||
|
||||
// Row 7, Column 1
|
||||
|`token_rule`
|
||||
// Row 7, Column 2
|
||||
|Match a string of characters from a character set.
|
||||
|
||||
// Row 8, Column 1
|
||||
|`tuple_rule`
|
||||
// Row 8, Column 2
|
||||
|Match a sequence of specified rules, in order.
|
||||
|
||||
// Row 9, Column 1
|
||||
|`unsigned_rule`
|
||||
// Row 9, Column 2
|
||||
|Match an unsigned integer in decimal form.
|
||||
|
||||
// Row 10, Column 1
|
||||
|`variant_rule`
|
||||
// Row 10, Column 2
|
||||
|Match one of a set of alternatives specified by rules.
|
||||
|
||||
|===
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//
|
||||
|
||||
|
||||
== RFC 3986
|
||||
= RFC 3986
|
||||
|
||||
Functions like `parse_uri` are sufficient for converting URLs but
|
||||
they require that the entire string is consumed. When URLs appear as
|
||||
@@ -16,9 +16,9 @@ components of a larger grammar, it is desired to use composition
|
||||
of rules based parsing to process these along with other elements
|
||||
potentially unrelated to resource locators. To achieve this, the
|
||||
library provides rules for the top-level BNF productions found
|
||||
in `rfc3986` and a rule for matching percent-encoded strings.
|
||||
in https://tools.ietf.org/html/rfc3986[rfc3986,window=blank_] and a rule for matching percent-encoded strings.
|
||||
|
||||
=== Percent Encoding
|
||||
== Percent Encoding
|
||||
|
||||
The percent-encoding mechanism is used to represent a data octet
|
||||
in a component when the corresponding character is outside the
|
||||
@@ -58,56 +58,63 @@ equality and comparison to unencoded strings, without allocating
|
||||
memory. In the example below we parse the string `s` as a
|
||||
series of zero or more `pchars`:
|
||||
|
||||
// code_grammar_5_1
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_5_1
|
||||
system::result< pct_string_view > rv = parse( s, pct_encoded_rule( pchars ) );
|
||||
----
|
||||
|
||||
|
||||
These constants are used and provided by the library to
|
||||
specify rules for percent-encoded URL components:
|
||||
|
||||
// [table URL Character Sets [
|
||||
// [Name]
|
||||
// [BNF]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__gen_delim_chars `gen_delim_chars`]]
|
||||
// [
|
||||
// ```
|
||||
// gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
|
||||
// ```
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__pchars `pchars`]]
|
||||
// [
|
||||
// ```
|
||||
// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
// ```
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__reserved_chars `reserved_chars`]]
|
||||
// [
|
||||
// (everything but
|
||||
// [link url.ref.boost__urls__unreserved_chars `unreserved_chars`])
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__sub_delim_chars `sub_delim_chars`]]
|
||||
// [
|
||||
// ```
|
||||
// sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
// / "*" / "+" / "," / ";" / "="
|
||||
// ```
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__unreserved_chars `unreserved_chars`]]
|
||||
// [
|
||||
// ```
|
||||
// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
// ```
|
||||
// ]
|
||||
// ]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Name|BNF
|
||||
|
||||
=== URL Rules
|
||||
// Row 1, Column 1
|
||||
|`gen_delim_chars`
|
||||
// Row 1, Column 2
|
||||
|[source]
|
||||
----
|
||||
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
|
||||
----
|
||||
|
||||
// Row 2, Column 1
|
||||
|`pchars`
|
||||
// Row 2, Column 2
|
||||
|[source]
|
||||
----
|
||||
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
----
|
||||
|
||||
// Row 3, Column 1
|
||||
|`reserved_chars`
|
||||
// Row 3, Column 2
|
||||
|(everything but `unreserved_chars`)
|
||||
|
||||
// Row 4, Column 1
|
||||
|`sub_delim_chars`
|
||||
// Row 4, Column 2
|
||||
|[source]
|
||||
----
|
||||
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
/ "*" / "+" / "," / ";" / "="
|
||||
----
|
||||
|
||||
// Row 5, Column 1
|
||||
|`unreserved_chars`
|
||||
// Row 5, Column 2
|
||||
|[source]
|
||||
----
|
||||
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
----
|
||||
|
||||
|===
|
||||
|
||||
|
||||
== URL Rules
|
||||
|
||||
When a URL can appear in the context of a larger grammar, it may
|
||||
be desired to express the enclosing grammar in a single rule that
|
||||
@@ -119,67 +126,90 @@ elements. Here we present a rule suitable for parsing the
|
||||
the HTTP
|
||||
https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.1[__request-line__,window=blank_]:
|
||||
|
||||
// code_grammar_5_2
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_5_2
|
||||
// request-line = method SP request-target SP HTTP-version CRLF
|
||||
|
||||
constexpr auto request_line_rule = tuple_rule(
|
||||
not_empty_rule( token_rule( alpha_chars ) ), // method
|
||||
squelch( delim_rule( ' ' ) ), // SP
|
||||
variant_rule(
|
||||
absolute_uri_rule, // absolute-uri or
|
||||
relative_ref_rule), // relative-ref
|
||||
squelch( delim_rule( ' ' ) ),
|
||||
squelch( literal_rule( "HTTP/" ) ), // "HTTP/"
|
||||
delim_rule( digit_chars ), // DIGIT
|
||||
squelch( delim_rule( '.' ) ), // "."
|
||||
delim_rule( digit_chars ), // DIGIT
|
||||
squelch( literal_rule( "\r\n" ) ) ); // CRLF
|
||||
----
|
||||
|
||||
|
||||
The library offers these rules to allow custom rule definitions
|
||||
to integrate the various styles of valid URL rules:
|
||||
|
||||
// [table RFC3986 Rules [
|
||||
// [Name]
|
||||
// [BNF]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__absolute_uri_rule `absolute_uri_rule`]]
|
||||
// [
|
||||
// ```
|
||||
// absolute-URI = scheme ":" hier-part [ "?" query ]
|
||||
//
|
||||
// hier-part = "//" authority path-abempty
|
||||
// / path-absolute
|
||||
// / path-rootless
|
||||
// / path-empty
|
||||
// ```
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__authority_rule `authority_rule`]]
|
||||
// [
|
||||
// ```
|
||||
// authority = [ userinfo "@" ] host [ ":" port ]
|
||||
// ```
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__origin_form_rule `origin_form_rule`]]
|
||||
// [
|
||||
// ```
|
||||
// origin-form = absolute-path [ "?" query ]
|
||||
//
|
||||
// absolute-path = 1*( "/" segment )
|
||||
// ```
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__relative_ref_rule `relative_ref_rule`]]
|
||||
// [
|
||||
// ```
|
||||
// relative-ref = relative-part [ "?" query ] [ "#" fragment ]
|
||||
// ```
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__uri_reference_rule `uri_reference_rule`]]
|
||||
// [
|
||||
// ```
|
||||
// URI-reference = URI / relative-ref
|
||||
// ```
|
||||
// ]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__uri_rule `uri_rule`]]
|
||||
// [
|
||||
// ```
|
||||
// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
|
||||
// ```
|
||||
// ]
|
||||
// ]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Name|BNF
|
||||
|
||||
// Row 1, Column 1
|
||||
|`absolute_uri_rule`
|
||||
// Row 1, Column 2
|
||||
|[source]
|
||||
----
|
||||
absolute-URI = scheme ":" hier-part [ "?" query ]
|
||||
|
||||
hier-part = "//" authority path-abempty
|
||||
/ path-absolute
|
||||
/ path-rootless
|
||||
/ path-empty
|
||||
----
|
||||
|
||||
// Row 2, Column 1
|
||||
|`authority_rule`
|
||||
// Row 2, Column 3
|
||||
|[source,cpp]
|
||||
----
|
||||
authority = [ userinfo "@" ] host [ ":" port ]
|
||||
----
|
||||
|
||||
// Row 3, Column 1
|
||||
|`origin_form_rule`
|
||||
// Row 3, Column 2
|
||||
|[source]
|
||||
----
|
||||
origin-form = absolute-path [ "?" query ]
|
||||
|
||||
absolute-path = 1*( "/" segment )
|
||||
----
|
||||
|
||||
// Row 4, Column 1
|
||||
|`relative_ref_rule`
|
||||
// Row 4, Column 2
|
||||
|[source]
|
||||
----
|
||||
relative-ref = relative-part [ "?" query ] [ "#" fragment ]
|
||||
----
|
||||
|
||||
// Row 5, Column 1
|
||||
|`uri_reference_rule`
|
||||
// Row 5, Column 2
|
||||
|[source,cpp]
|
||||
----
|
||||
URI-reference = URI / relative-ref
|
||||
----
|
||||
|
||||
// Row 6, Column 1
|
||||
|`uri_rule`
|
||||
// Row 6, Column 2
|
||||
|[source,cpp]
|
||||
----
|
||||
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
|
||||
----
|
||||
|
||||
|===
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
//
|
||||
|
||||
|
||||
== Parse Rules
|
||||
= Parse Rules
|
||||
|
||||
A `Rule` is an object which tries to match the beginning of
|
||||
A __Rule__ is an object which tries to match the beginning of
|
||||
an input character buffer against a particular syntax.
|
||||
It returns a `result` containing a value if the match
|
||||
was successful, or an `error_code` if the match failed.
|
||||
@@ -24,19 +24,38 @@ parsed sequentially:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_1_1
|
||||
template< class Rule >
|
||||
auto parse( core::string_view s, Rule const& r) -> system::result< typename Rule::value_type >;
|
||||
|
||||
template< class Rule >
|
||||
auto parse( char const *& it, char const* end, Rule const& r) -> system::result< typename Rule::value_type >;
|
||||
----
|
||||
|
||||
|
||||
To satisfy the `Rule` concept, a `class` or `struct` must declare
|
||||
To satisfy the __Rule__ concept, a `class` or `struct` must declare
|
||||
the nested type `value_type` indicating the type of value returned
|
||||
upon success, and a `const` member function `parse` with a prescribed
|
||||
signature. In the following code we define a rule that matches a
|
||||
single comma:
|
||||
|
||||
// code_grammar_1_2
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_1_2
|
||||
struct comma_rule_t
|
||||
{
|
||||
// The type of value returned upon success
|
||||
using value_type = core::string_view;
|
||||
|
||||
// The algorithm which checks for a match
|
||||
system::result< value_type >
|
||||
parse( char const*& it, char const* end ) const
|
||||
{
|
||||
if( it != end && *it == ',')
|
||||
return core::string_view( it++, 1 );
|
||||
|
||||
return error::mismatch;
|
||||
}
|
||||
};
|
||||
----
|
||||
|
||||
|
||||
@@ -44,18 +63,22 @@ Since rules are passed by value, we declare a `constexpr` variable
|
||||
of the type for syntactical convenience. Variable names for rules
|
||||
are usually suffixed with `_rule`:
|
||||
|
||||
// code_grammar_1_3
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_1_3
|
||||
constexpr comma_rule_t comma_rule{};
|
||||
----
|
||||
|
||||
|
||||
Now we can call `parse` with the string of input and the rule
|
||||
variable thusly:
|
||||
|
||||
// code_grammar_1_4
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_1_4
|
||||
system::result< core::string_view > rv = parse( ",", comma_rule );
|
||||
|
||||
assert( rv.has_value() && rv.value() == "," );
|
||||
----
|
||||
|
||||
|
||||
@@ -65,9 +88,10 @@ an unsigned decimal integer. Here we construct the rule at
|
||||
run time and specify the type of unsigned integer used to
|
||||
hold the result with a template parameter:
|
||||
|
||||
// code_grammar_1_5
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_1_5
|
||||
system::result< unsigned short > rv = parse( "16384", unsigned_rule< unsigned short >{} );
|
||||
----
|
||||
|
||||
|
||||
@@ -76,13 +100,14 @@ passed character literal. This is a more general version of the
|
||||
comma rule which we defined earlier. There is also an overload
|
||||
which matches exactly one character from a character set.
|
||||
|
||||
// code_grammar_1_6
|
||||
[source,cpp]
|
||||
----
|
||||
// code_grammar_1_6
|
||||
system::result< core::string_view > rv = parse( ",", delim_rule(',') );
|
||||
----
|
||||
|
||||
|
||||
=== Error Handling
|
||||
== Error Handling
|
||||
|
||||
When a rule fails to match, or if the rule detects a
|
||||
unrecoverable problem with the input, it returns a
|
||||
@@ -97,7 +122,7 @@ in the input, or to the `end` pointer if all input
|
||||
was consumed.
|
||||
|
||||
It is the responsibilty of library and user-defined
|
||||
implementations of __compound__ (explained later)
|
||||
implementations of __compound rules__ (explained later)
|
||||
to rewind their internal pointer if a parsing operation
|
||||
was unsuccessful, and they wish to attempt parsing the
|
||||
same input using a different rule.
|
||||
|
||||
@@ -7,16 +7,12 @@
|
||||
// Official repository: https://github.com/boostorg/url
|
||||
//
|
||||
|
||||
|
||||
== Boost.URL
|
||||
|
||||
|
||||
|
||||
= Boost.URL
|
||||
|
||||
Boost.URL is a portable C++ library which provides containers and algorithms
|
||||
which model a "URL," more formally described using the
|
||||
https://datatracker.ietf.org/doc/html/rfc3986[Uniform Resource Identifier (URI),window=blank_]
|
||||
specification (henceforth referred to as `rfc3986`). A URL is a compact sequence
|
||||
specification (henceforth referred to as https://tools.ietf.org/html/rfc3986[rfc3986,window=blank_]). A URL is a compact sequence
|
||||
of characters that identifies an abstract or physical resource. For example,
|
||||
this is a valid URL:
|
||||
|
||||
@@ -31,7 +27,7 @@ This library understands the grammars related to URLs and provides
|
||||
functionality to validate, parse, examine, and modify urls, and apply
|
||||
normalization or resolution algorithms.
|
||||
|
||||
=== Features
|
||||
== Features
|
||||
|
||||
While the library is general purpose, special care has been taken to ensure
|
||||
that the implementation and data representation are friendly to network
|
||||
@@ -47,23 +43,25 @@ Boost.URL offers these features:
|
||||
|
||||
* C++11 as only requirement
|
||||
* Fast compilation, few templates
|
||||
* Strict compliance with `rfc3986`
|
||||
* Strict compliance with https://tools.ietf.org/html/rfc3986[rfc3986,window=blank_]
|
||||
* Containers that maintain valid URLs
|
||||
* Parsing algorithms that work without exceptions
|
||||
* Control over storage and allocation for URLs
|
||||
* Support for `-fno-exceptions`, detected automatically
|
||||
* Features that work well on embedded devices
|
||||
|
||||
// [note
|
||||
// Currently the library does not handle
|
||||
// [@https://www.rfc-editor.org/rfc/rfc3987.html Internationalized Resource Identifiers] (IRIs).
|
||||
// These are different from URLs, come from Unicode strings instead of
|
||||
// low-ASCII strings, and are covered by a separate specification.
|
||||
// ]
|
||||
[NOTE]
|
||||
====
|
||||
Currently the library does not handle
|
||||
https://www.rfc-editor.org/rfc/rfc3987.html[Internationalized Resource Identifiers,window=blank_] (IRIs).
|
||||
These are different from URLs, come from Unicode strings instead of
|
||||
low-ASCII strings, and are covered by a separate specification.
|
||||
====
|
||||
|
||||
|
||||
|
||||
=== Requirements
|
||||
|
||||
== Requirements
|
||||
|
||||
The library requires a compiler supporting at least C++11.
|
||||
|
||||
@@ -79,7 +77,7 @@ desired.
|
||||
|
||||
|
||||
|
||||
=== Tested Compilers
|
||||
== Tested Compilers
|
||||
|
||||
Boost.URL has been tested with the following compilers:
|
||||
|
||||
@@ -91,7 +89,7 @@ and these architectures: x86, x64, ARM64, S390x.
|
||||
|
||||
We do not test and support gcc 8.0.1.
|
||||
|
||||
=== Quality Assurance
|
||||
== Quality Assurance
|
||||
|
||||
The development infrastructure for the library includes
|
||||
these per-commit analyses:
|
||||
@@ -102,7 +100,7 @@ these per-commit analyses:
|
||||
|
||||
|
||||
|
||||
=== Nomenclature
|
||||
== Nomenclature
|
||||
|
||||
Various names have been used historically to refer to different
|
||||
flavors of resource identifiers, including __URI__, __URL__, __URN__,
|
||||
@@ -110,13 +108,13 @@ and even __IRI__. Over time, the distinction between URIs and URLs
|
||||
has disappeared when discussed in technical documents and
|
||||
informal works. In this library we use the term **URL** to
|
||||
refer to all strings which are valid according to the
|
||||
top-level grammar rules found in `rfc3986`.
|
||||
top-level grammar rules found in https://tools.ietf.org/html/rfc3986[rfc3986,window=blank_].
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
=== ABNF
|
||||
== ABNF
|
||||
|
||||
This documentation uses the Augmented
|
||||
https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form[Backus-Naur Form,window=blank_]
|
||||
@@ -131,7 +129,7 @@ the library.
|
||||
|
||||
|
||||
|
||||
=== Acknowledgments
|
||||
== Acknowledgments
|
||||
|
||||
This library wouldn't be where it is today without the help of
|
||||
https://github.com/pdimov[Peter Dimov,window=blank_]
|
||||
@@ -139,6 +137,6 @@ for design advice and general assistance.
|
||||
|
||||
|
||||
|
||||
// [include 2.0.quicklook.qbk]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,19 +8,26 @@
|
||||
//
|
||||
|
||||
|
||||
== Quick Look
|
||||
= Quick Look
|
||||
|
||||
This section is intended to give the reader a brief overview of the features
|
||||
and interface style of the library.
|
||||
|
||||
=== Integration
|
||||
== Integration
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Sample code and identifiers used throughout are written as if
|
||||
the following declarations are in effect:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
#include <boost/url.hpp>
|
||||
using namespace boost::urls;
|
||||
----
|
||||
|
||||
====
|
||||
|
||||
// [note
|
||||
// Sample code and identifiers used throughout are written as if
|
||||
// the following declarations are in effect:
|
||||
//
|
||||
// [snippet_headers_3]
|
||||
// ]
|
||||
|
||||
We begin by including the library header file which brings all the symbols into
|
||||
scope.
|
||||
@@ -28,7 +35,7 @@ scope.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_headers_1
|
||||
#include <boost/url.hpp>
|
||||
----
|
||||
|
||||
|
||||
@@ -41,14 +48,15 @@ You must install binaries in a location that can be found by your linker.
|
||||
If you followed the http://www.boost.org/doc/libs/release/more/getting_started/index.html[Boost Getting Started,window=blank_]
|
||||
instructions, that's already been done for you.
|
||||
|
||||
=== Parsing
|
||||
== Parsing
|
||||
|
||||
Say you have the following URL that you want to parse:
|
||||
|
||||
|
||||
// code_urls_parsing_1
|
||||
[source,cpp]
|
||||
----
|
||||
// code_urls_parsing_1
|
||||
boost::core::string_view s = "https://user:pass@example.com:443/path/to/my%2dfile.txt?id=42&name=John%20Doe+Jingleheimer%2DSchmidt#page%20anchor";
|
||||
----
|
||||
|
||||
|
||||
@@ -59,9 +67,10 @@ The library namespace includes the aliases `string_view`, `error_code`, and
|
||||
|
||||
You can parse the string by calling this function:
|
||||
|
||||
// code_urls_parsing_2
|
||||
[source,cpp]
|
||||
----
|
||||
// code_urls_parsing_2
|
||||
boost::system::result<url_view> r = parse_uri( s );
|
||||
----
|
||||
|
||||
|
||||
@@ -71,17 +80,19 @@ A number of functions are available to parse different types of URL.
|
||||
|
||||
We can immediately call `result::value` to obtain a `url_view`.
|
||||
|
||||
// snippet_parsing_3
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_parsing_3
|
||||
url_view u = r.value();
|
||||
----
|
||||
|
||||
|
||||
Or simply
|
||||
|
||||
// snippet_parsing_4
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_parsing_4
|
||||
url_view u = *r;
|
||||
----
|
||||
|
||||
|
||||
@@ -95,52 +106,85 @@ https://www.boost.org/doc/libs/1_83_0//libs/system/doc/html/system.html#ref_quer
|
||||
https://www.boost.org/doc/libs/1_83_0//libs/system/doc/html/system.html#ref_queries[`result::has_error`,window=blank_] could
|
||||
also be used to check if the string has been parsed without errors.
|
||||
|
||||
// [note
|
||||
// It is worth noting that __parse_uri__ does not allocate any memory dynamically.
|
||||
// Like a __string_view__, a __url_view__ does not retain ownership of the underlying
|
||||
// string buffer.
|
||||
//
|
||||
// As long as the contents of the original string are unmodified, constructed
|
||||
// URL views always contain a valid URL in its correctly serialized form.
|
||||
//
|
||||
// If the input does not match the URL grammar, an error code
|
||||
// is reported through __result__ rather than exceptions.
|
||||
// Exceptions only thrown on excessive input length.
|
||||
// ]
|
||||
[NOTE]
|
||||
====
|
||||
It is worth noting that `parse_uri` does not allocate any memory dynamically.
|
||||
Like a `string_view`, a `url_view` does not retain ownership of the underlying
|
||||
string buffer.
|
||||
|
||||
=== Accessing
|
||||
As long as the contents of the original string are unmodified, constructed
|
||||
URL views always contain a valid URL in its correctly serialized form.
|
||||
|
||||
If the input does not match the URL grammar, an error code
|
||||
is reported through `result` rather than exceptions.
|
||||
Exceptions only thrown on excessive input length.
|
||||
====
|
||||
|
||||
|
||||
== Accessing
|
||||
|
||||
Accessing the parts of the URL is easy:
|
||||
|
||||
// snippet_accessing_1
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_accessing_1
|
||||
url_view u( "https://user:pass@example.com:443/path/to/my%2dfile.txt?id=42&name=John%20Doe+Jingleheimer%2DSchmidt#page%20anchor" );
|
||||
assert(u.scheme() == "https");
|
||||
assert(u.authority().buffer() == "user:pass@example.com:443");
|
||||
assert(u.userinfo() == "user:pass");
|
||||
assert(u.user() == "user");
|
||||
assert(u.password() == "pass");
|
||||
assert(u.host() == "example.com");
|
||||
assert(u.port() == "443");
|
||||
assert(u.path() == "/path/to/my-file.txt");
|
||||
assert(u.query() == "id=42&name=John Doe Jingleheimer-Schmidt");
|
||||
assert(u.fragment() == "page anchor");
|
||||
----
|
||||
|
||||
|
||||
URL paths can be further divided into path segments with
|
||||
the function `url_view::segments`.
|
||||
Although URL query strings are often used to represent key/value pairs, this
|
||||
interpretation is not defined by `rfc3986`.
|
||||
interpretation is not defined by https://tools.ietf.org/html/rfc3986[rfc3986,window=blank_].
|
||||
Users can treat the query as a single entity.
|
||||
`url_view` provides the function
|
||||
`url_view::params` to extract this view
|
||||
of key/value pairs.
|
||||
|
||||
// [table [[Code][Output]] [[
|
||||
// [c++]
|
||||
// [snippet_accessing_1b]
|
||||
// ][
|
||||
// [teletype]
|
||||
// ```
|
||||
// path
|
||||
// to
|
||||
// my-file.txt
|
||||
//
|
||||
// id: 42
|
||||
// name: John Doe Jingleheimer-Schmidt
|
||||
// ```
|
||||
// ]]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Code|Output
|
||||
|
||||
// Row 1, Column 1
|
||||
|
|
||||
// snippet_accessing_1b
|
||||
[source,cpp]
|
||||
----
|
||||
for (auto seg: u.segments())
|
||||
std::cout << seg << "\n";
|
||||
std::cout << "\n";
|
||||
|
||||
for (auto param: u.params())
|
||||
std::cout << param.key << ": " << param.value << "\n";
|
||||
std::cout << "\n";
|
||||
----
|
||||
|
||||
// Row 1, Column 2
|
||||
|
|
||||
[source]
|
||||
----
|
||||
path
|
||||
to
|
||||
my-file.txt
|
||||
|
||||
id: 42
|
||||
name: John Doe Jingleheimer-Schmidt
|
||||
----
|
||||
|
||||
|
||||
|===
|
||||
|
||||
|
||||
These functions return views referring to substrings and sub-ranges
|
||||
of the underlying URL.
|
||||
@@ -148,33 +192,44 @@ By simply referencing the relevant portion of the URL string internally,
|
||||
its components can represent percent-decoded strings and be converted
|
||||
to other types without any previous memory allocation.
|
||||
|
||||
// snippet_token_1
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_token_1
|
||||
std::string h = u.host();
|
||||
assert(h == "example.com");
|
||||
----
|
||||
|
||||
|
||||
A special `string_token` type can also be used to specify how a portion of the URL should be encoded and returned.
|
||||
|
||||
// snippet_token_2
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_token_2
|
||||
std::string h = "host: ";
|
||||
u.host(string_token::append_to(h));
|
||||
assert(h == "host: example.com");
|
||||
----
|
||||
|
||||
|
||||
These functions might also return empty strings
|
||||
|
||||
// snippet_accessing_2a
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_accessing_2a
|
||||
url_view u1 = parse_uri( "http://www.example.com" ).value();
|
||||
assert(u1.fragment().empty());
|
||||
assert(!u1.has_fragment());
|
||||
----
|
||||
|
||||
|
||||
for both empty and absent components
|
||||
|
||||
// snippet_accessing_2b
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_accessing_2b
|
||||
url_view u2 = parse_uri( "http://www.example.com/#" ).value();
|
||||
assert(u2.fragment().empty());
|
||||
assert(u2.has_fragment());
|
||||
----
|
||||
|
||||
|
||||
@@ -187,40 +242,80 @@ When applicable, the encoded components can also be directly
|
||||
accessed through a `string_view` without any
|
||||
need to allocate memory:
|
||||
|
||||
// [table [[Code][Output]] [[
|
||||
// [c++]
|
||||
// [snippet_accessing_4]
|
||||
// ][
|
||||
// [teletype]
|
||||
// ```
|
||||
// url : https://user:pass@example.com:443/path/to/my%2dfile.txt?id=42&name=John%20Doe+Jingleheimer%2DSchmidt#page%20anchor
|
||||
// scheme : https
|
||||
// authority : user:pass@example.com:443
|
||||
// userinfo : user:pass
|
||||
// user : user
|
||||
// password : pass
|
||||
// host : example.com
|
||||
// port : 443
|
||||
// path : /path/to/my%2dfile.txt
|
||||
// query : id=42&name=John%20Doe+Jingleheimer%2DSchmidt
|
||||
// fragment : page%20anchor
|
||||
// ```
|
||||
// ]]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Code|Output
|
||||
|
||||
=== Percent-Encoding
|
||||
// Row 1, Column 1
|
||||
|
|
||||
// snippet_accessing_4
|
||||
[source,cpp]
|
||||
----
|
||||
std::cout <<
|
||||
"url : " << u << "\n"
|
||||
"scheme : " << u.scheme() << "\n"
|
||||
"authority : " << u.encoded_authority() << "\n"
|
||||
"userinfo : " << u.encoded_userinfo() << "\n"
|
||||
"user : " << u.encoded_user() << "\n"
|
||||
"password : " << u.encoded_password() << "\n"
|
||||
"host : " << u.encoded_host() << "\n"
|
||||
"port : " << u.port() << "\n"
|
||||
"path : " << u.encoded_path() << "\n"
|
||||
"query : " << u.encoded_query() << "\n"
|
||||
"fragment : " << u.encoded_fragment() << "\n";
|
||||
----
|
||||
|
||||
// Row 1, Column 2
|
||||
|
|
||||
[source]
|
||||
----
|
||||
url : https://user:pass@example.com:443/path/to/my%2dfile.txt?id=42&name=John%20Doe+Jingleheimer%2DSchmidt#page%20anchor
|
||||
scheme : https
|
||||
authority : user:pass@example.com:443
|
||||
userinfo : user:pass
|
||||
user : user
|
||||
password : pass
|
||||
host : example.com
|
||||
port : 443
|
||||
path : /path/to/my%2dfile.txt
|
||||
query : id=42&name=John%20Doe+Jingleheimer%2DSchmidt
|
||||
fragment : page%20anchor
|
||||
----
|
||||
|
||||
|
||||
|===
|
||||
|
||||
|
||||
== Percent-Encoding
|
||||
|
||||
An instance of `decode_view` provides a number of functions
|
||||
to persist a decoded string:
|
||||
|
||||
// [table [[Code][Output]] [[
|
||||
// [c++]
|
||||
// [snippet_decoding_1]
|
||||
// ][
|
||||
// [teletype]
|
||||
// ```
|
||||
// id=42&name=John Doe Jingleheimer-Schmidt
|
||||
// ```
|
||||
// ]]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Code|Output
|
||||
|
||||
// Row 1, Column 1
|
||||
|
|
||||
// snippet_decoding_1
|
||||
[source,cpp]
|
||||
----
|
||||
decode_view dv("id=42&name=John%20Doe%20Jingleheimer%2DSchmidt");
|
||||
std::cout << dv << "\n";
|
||||
----
|
||||
|
||||
// Row 1, Column 2
|
||||
|
|
||||
[source]
|
||||
----
|
||||
id=42&name=John Doe Jingleheimer-Schmidt
|
||||
----
|
||||
|
||||
|
||||
|===
|
||||
|
||||
|
||||
`decode_view` and its decoding functions are designed to
|
||||
perform no memory allocations unless the algorithm where its being
|
||||
@@ -243,15 +338,32 @@ If `u2.host()` returned a value type, then two memory allocations
|
||||
would be necessary for this operation. Another common use case
|
||||
is converting URL path segments into filesystem paths:
|
||||
|
||||
// [table [[Code][Output]] [[
|
||||
// [c++]
|
||||
// [snippet_decoding_3]
|
||||
// ][
|
||||
// [teletype]
|
||||
// ```
|
||||
// path: "path/to/my-file.txt"
|
||||
// ```
|
||||
// ]]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Code|Output
|
||||
|
||||
// Row 1, Column 1
|
||||
|
|
||||
// snippet_decoding_3
|
||||
[source,cpp]
|
||||
----
|
||||
boost::filesystem::path p;
|
||||
for (auto seg: u.segments())
|
||||
p.append(seg.begin(), seg.end());
|
||||
std::cout << "path: " << p << "\n";
|
||||
----
|
||||
|
||||
// Row 1, Column 2
|
||||
|
|
||||
[source]
|
||||
----
|
||||
path: "path/to/my-file.txt"
|
||||
----
|
||||
|
||||
|
||||
|===
|
||||
|
||||
|
||||
In this example, only the internal allocations of
|
||||
`filesystem::path` need to happen. In many common
|
||||
@@ -260,9 +372,21 @@ such as finding the appropriate route for a URL
|
||||
in a web server:
|
||||
|
||||
|
||||
// snippet_decoding_4a
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_decoding_4a
|
||||
auto match = [](
|
||||
std::vector<std::string> const& route,
|
||||
url_view u)
|
||||
{
|
||||
auto segs = u.segments();
|
||||
if (route.size() != segs.size())
|
||||
return false;
|
||||
return std::equal(
|
||||
route.begin(),
|
||||
route.end(),
|
||||
segs.begin());
|
||||
};
|
||||
----
|
||||
|
||||
|
||||
@@ -270,14 +394,20 @@ This allows us to easily match files in the document
|
||||
root directory of a web server:
|
||||
|
||||
|
||||
// snippet_decoding_4b
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_decoding_4b
|
||||
std::vector<std::string> route =
|
||||
{"community", "reviews.html"};
|
||||
if (match(route, u))
|
||||
{
|
||||
handle_route(route, u);
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
// [#compound-elements]
|
||||
=== Compound elements
|
||||
== Compound elements
|
||||
|
||||
The path and query parts of the URL are treated specially by the library.
|
||||
While they can be accessed as individual encoded strings, they can also be
|
||||
@@ -286,16 +416,34 @@ accessed through special view types.
|
||||
This code calls
|
||||
`encoded_segments`
|
||||
to obtain the path segments as a container that returns encoded strings:
|
||||
// [table [[Code][Output]] [[
|
||||
// [c++]
|
||||
// [snippet_compound_elements_1]
|
||||
// ][
|
||||
// ```
|
||||
// path
|
||||
// to
|
||||
// my-file.txt
|
||||
// ```
|
||||
// ]]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Code|Output
|
||||
|
||||
// Row 1, Column 1
|
||||
|
|
||||
// snippet_compound_elements_1
|
||||
[source,cpp]
|
||||
----
|
||||
segments_encoded_view segs = u.encoded_segments();
|
||||
for( auto v : segs )
|
||||
{
|
||||
std::cout << v << "\n";
|
||||
}
|
||||
----
|
||||
|
||||
// Row 1, Column 2
|
||||
|[source,cpp]
|
||||
----
|
||||
path
|
||||
to
|
||||
my-file.txt
|
||||
----
|
||||
|
||||
|
||||
|===
|
||||
|
||||
|
||||
As with other `url_view` functions which return encoded strings, the encoded
|
||||
segments container does not allocate memory. Instead it returns views to the
|
||||
@@ -304,30 +452,68 @@ corresponding portions of the underlying encoded buffer referenced by the URL.
|
||||
As with other library functions, `decode_view` permits accessing
|
||||
elements of composed elements while avoiding memory allocations entirely:
|
||||
|
||||
// [table [[Code][Output]] [[
|
||||
// [c++]
|
||||
// [snippet_encoded_compound_elements_1]
|
||||
// ][
|
||||
// [teletype]
|
||||
// ```
|
||||
// path
|
||||
// to
|
||||
// my-file.txt
|
||||
// ```
|
||||
// ]][[
|
||||
// [c++]
|
||||
// [snippet_encoded_compound_elements_2]
|
||||
// ][
|
||||
// [teletype]
|
||||
// ```
|
||||
// key = id, value = 42
|
||||
// key = name, value = John Doe
|
||||
// ```
|
||||
// ]]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Code|Output
|
||||
|
||||
// Row 1, Column 1
|
||||
|
|
||||
// snippet_encoded_compound_elements_1
|
||||
[source,cpp]
|
||||
----
|
||||
segments_encoded_view segs = u.encoded_segments();
|
||||
|
||||
for( pct_string_view v : segs )
|
||||
{
|
||||
decode_view dv = *v;
|
||||
std::cout << dv << "\n";
|
||||
}
|
||||
----
|
||||
|
||||
// Row 1, Column 2
|
||||
|
|
||||
[source]
|
||||
----
|
||||
path
|
||||
to
|
||||
my-file.txt
|
||||
----
|
||||
|
||||
|
||||
// Row 2, Column 1
|
||||
|
|
||||
// snippet_encoded_compound_elements_2
|
||||
[source,cpp]
|
||||
----
|
||||
params_encoded_view params_ref = u.encoded_params();
|
||||
|
||||
for( auto v : params_ref )
|
||||
{
|
||||
decode_view dk(v.key);
|
||||
decode_view dv(v.value);
|
||||
|
||||
std::cout <<
|
||||
"key = " << dk <<
|
||||
", value = " << dv << "\n";
|
||||
}
|
||||
----
|
||||
|
||||
// Row 2, Column 2
|
||||
|
|
||||
[source]
|
||||
----
|
||||
key = id, value = 42
|
||||
key = name, value = John Doe
|
||||
----
|
||||
|
||||
|
||||
|===
|
||||
|
||||
|
||||
|
||||
=== Modifying
|
||||
|
||||
== Modifying
|
||||
|
||||
The library provides the containers `url` and `static_url` which supporting
|
||||
modification of the URL contents. A `url` or `static_url` must be constructed
|
||||
@@ -338,9 +524,10 @@ character buffer, the `url` container uses the default allocator to
|
||||
control a resizable character buffer which it owns.
|
||||
|
||||
|
||||
// snippet_quicklook_modifying_1
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_quicklook_modifying_1
|
||||
url u = parse_uri( s ).value();
|
||||
----
|
||||
|
||||
|
||||
@@ -348,9 +535,10 @@ On the other hand, a `static_url` has fixed-capacity storage and does
|
||||
not require dynamic memory allocations.
|
||||
|
||||
|
||||
// snippet_quicklook_modifying_1b
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_quicklook_modifying_1b
|
||||
static_url<1024> su = parse_uri( s ).value();
|
||||
----
|
||||
|
||||
|
||||
@@ -361,17 +549,19 @@ constructible, and equality comparable. They support all the inspection function
|
||||
|
||||
Changing the scheme is easy:
|
||||
|
||||
// snippet_quicklook_modifying_2
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_quicklook_modifying_2
|
||||
u.set_scheme( "https" );
|
||||
----
|
||||
|
||||
|
||||
Or we can use a predefined constant:
|
||||
|
||||
// snippet_quicklook_modifying_3
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_quicklook_modifying_3
|
||||
u.set_scheme_id( scheme::https ); // equivalent to u.set_scheme( "https" );
|
||||
----
|
||||
|
||||
|
||||
@@ -386,29 +576,62 @@ It is not possible for a `url` to hold syntactically illegal text.
|
||||
Modification functions return a reference to the object, so chaining
|
||||
is possible:
|
||||
|
||||
// [table [[Code][Output]] [[
|
||||
// [c++]
|
||||
// [snippet_quicklook_modifying_4]
|
||||
// ][
|
||||
// [teletype]
|
||||
// ```
|
||||
// https://192.168.0.1:8080/path/to/my%2dfile.txt?id=42&name=John%20Doe#page%20anchor
|
||||
// ```
|
||||
// ]]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Code|Output
|
||||
|
||||
// Row 1, Column 1
|
||||
|
|
||||
// snippet_quicklook_modifying_4
|
||||
[source,cpp]
|
||||
----
|
||||
u.set_host_ipv4( ipv4_address( "192.168.0.1" ) )
|
||||
.set_port_number( 8080 )
|
||||
.remove_userinfo();
|
||||
std::cout << u << "\n";
|
||||
----
|
||||
|
||||
// Row 1, Column 2
|
||||
|
|
||||
[source]
|
||||
----
|
||||
https://192.168.0.1:8080/path/to/my%2dfile.txt?id=42&name=John%20Doe#page%20anchor
|
||||
----
|
||||
|
||||
|
||||
|===
|
||||
|
||||
|
||||
All non-const operations offer the strong exception safety guarantee.
|
||||
|
||||
The path segment and query parameter containers returned by a `url` offer
|
||||
modifiable range functionality, using member functions of the container:
|
||||
|
||||
// [table [[Code][Output]] [[
|
||||
// [c++]
|
||||
// [snippet_quicklook_modifying_5]
|
||||
// ][
|
||||
// [teletype]
|
||||
// ```
|
||||
// https://192.168.0.1:8080/path/to/my%2dfile.txt?id=42&name=Vinnie%20Falco#page%20anchor
|
||||
// ```
|
||||
// ]]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Code|Output
|
||||
|
||||
// Row 1, Column 1
|
||||
|
|
||||
// snippet_quicklook_modifying_5
|
||||
[source,cpp]
|
||||
----
|
||||
params_ref p = u.params();
|
||||
p.replace(p.find("name"), {"name", "John Doe"});
|
||||
std::cout << u << "\n";
|
||||
----
|
||||
|
||||
// Row 1, Column 2
|
||||
|
|
||||
[source]
|
||||
----
|
||||
https://192.168.0.1:8080/path/to/my%2dfile.txt?id=42&name=Vinnie%20Falco#page%20anchor
|
||||
----
|
||||
|
||||
|
||||
|===
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,21 +8,23 @@
|
||||
//
|
||||
|
||||
|
||||
== Formatting
|
||||
= Formatting
|
||||
|
||||
Algorithms to format URLs construct a mutable URL by parsing and applying
|
||||
arguments to a URL template. The following example uses the `format`
|
||||
function to construct an absolute URL:
|
||||
|
||||
|
||||
// snippet_format_1
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_format_1
|
||||
url u = format("{}://{}:{}/rfc/{}", "https", "www.ietf.org", 80, "rfc2396.txt");
|
||||
assert(u.buffer() == "https://www.ietf.org:80/rfc/rfc2396.txt");
|
||||
----
|
||||
|
||||
|
||||
The rules for a format URL string are the same
|
||||
as for a `std::format_string`, where replacement
|
||||
as for a https://en.cppreference.com/w/cpp/utility/format/basic_format_string[`std::format_string`,window=blank_], where replacement
|
||||
fields are delimited by curly braces. The URL
|
||||
type is inferred from the format string.
|
||||
|
||||
@@ -32,9 +34,11 @@ applied and any invalid characters for that
|
||||
formatted argument are percent-escaped:
|
||||
|
||||
|
||||
// snippet_format_2
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_format_2
|
||||
url u = format("https://{}/{}", "www.boost.org", "Hello world!");
|
||||
assert(u.buffer() == "https://www.boost.org/Hello%20world!");
|
||||
----
|
||||
|
||||
|
||||
@@ -45,16 +49,25 @@ characters are normalized to ensure the URL is
|
||||
valid:
|
||||
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_format_3a
|
||||
----
|
||||
|
||||
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
url u = format("{}:{}", "mailto", "someone@example.com");
|
||||
assert(u.buffer() == "mailto:someone@example.com");
|
||||
assert(u.scheme() == "mailto");
|
||||
assert(u.path() == "someone@example.com");
|
||||
----
|
||||
|
||||
|
||||
|
||||
// snippet_format_3b
|
||||
[source,cpp]
|
||||
----
|
||||
url u = format("{}{}", "mailto:", "someone@example.com");
|
||||
assert(u.buffer() == "mailto%3Asomeone@example.com");
|
||||
assert(!u.has_scheme());
|
||||
assert(u.path() == "mailto:someone@example.com");
|
||||
assert(u.encoded_path() == "mailto%3Asomeone@example.com");
|
||||
----
|
||||
|
||||
|
||||
@@ -62,19 +75,24 @@ The function `format_to` can be used to format URLs
|
||||
into any modifiable URL container.
|
||||
|
||||
|
||||
// snippet_format_4
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_format_4
|
||||
static_url<50> u;
|
||||
format_to(u, "{}://{}:{}/rfc/{}", "https", "www.ietf.org", 80, "rfc2396.txt");
|
||||
assert(u.buffer() == "https://www.ietf.org:80/rfc/rfc2396.txt");
|
||||
----
|
||||
|
||||
|
||||
As with `std::format`, positional and named arguments are
|
||||
As with https://en.cppreference.com/w/cpp/utility/format/format[`std::format`,window=blank_], positional and named arguments are
|
||||
supported.
|
||||
|
||||
|
||||
// snippet_format_5a
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_format_5a
|
||||
url u = format("{0}://{2}:{1}/{3}{4}{3}", "https", 80, "www.ietf.org", "abra", "cad");
|
||||
assert(u.buffer() == "https://www.ietf.org:80/abracadabra");
|
||||
----
|
||||
|
||||
|
||||
@@ -82,21 +100,26 @@ The `arg` function can be used to associate names
|
||||
with arguments:
|
||||
|
||||
|
||||
// snippet_format_5b
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_format_5b
|
||||
url u = format("https://example.com/~{username}", arg("username", "mark"));
|
||||
assert(u.buffer() == "https://example.com/~mark");
|
||||
----
|
||||
|
||||
|
||||
A second overload based on `std::initializer_list`
|
||||
A second overload based on https://en.cppreference.com/w/cpp/utility/initializer_list[`std::initializer_list`,window=blank_]
|
||||
is provided for both `format` and `format_to`.
|
||||
These overloads can help with lists of named
|
||||
arguments:
|
||||
|
||||
|
||||
// snippet_format_5c
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_format_5c
|
||||
boost::core::string_view fmt = "{scheme}://{host}:{port}/{dir}/{file}";
|
||||
url u = format(fmt, {{"scheme", "https"}, {"port", 80}, {"host", "example.com"}, {"dir", "path/to"}, {"file", "file.txt"}});
|
||||
assert(u.buffer() == "https://example.com:80/path/to/file.txt");
|
||||
----
|
||||
|
||||
|
||||
|
||||
@@ -8,17 +8,17 @@
|
||||
//
|
||||
|
||||
|
||||
== URLs
|
||||
= URLs
|
||||
|
||||
A URL, short for "Uniform Resource Locator," is a compact string
|
||||
of characters identifying an abstract or physical resource.
|
||||
It has these five parts, with may be optional or disallowed
|
||||
depending on the context:
|
||||
|
||||
// [$url/images/PartsDiagram.svg]
|
||||
image:PartsDiagram.svg[]
|
||||
|
||||
Each part's syntax is defined by a set of production rules in
|
||||
`rfc3986`. All valid URLs conform to this grammar, also called
|
||||
https://tools.ietf.org/html/rfc3986[rfc3986,window=blank_]. All valid URLs conform to this grammar, also called
|
||||
the "generic syntax." Here is an example URL which describes a
|
||||
file and its location on a network host:
|
||||
|
||||
@@ -31,40 +31,55 @@ https://www.example.com/path/to/file.txt?userid=1001&pages=3&results=full#page1
|
||||
|
||||
The parts and their corresponding text is as follows:
|
||||
|
||||
// [table Example Parts [
|
||||
// [Part]
|
||||
// [Text]
|
||||
// ][
|
||||
// [[link url.urls.containers.scheme ['scheme]]]
|
||||
// ["https"]
|
||||
// ][
|
||||
// [[link url.urls.containers.authority ['authority]]]
|
||||
// ["www.example.com"]
|
||||
// ][
|
||||
// [[link url.urls.containers.path ['path]]]
|
||||
// ["/path/to/file.txt"]
|
||||
// ][
|
||||
// [[link url.urls.containers.query ['query]]]
|
||||
// ["userid=1001&pages=3&results=full"]
|
||||
// ][
|
||||
// [[link url.urls.containers.fragment ['fragment]]]
|
||||
// ["page1"]
|
||||
// ]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Part|Text
|
||||
|
||||
// Row 1, Column 1
|
||||
|__scheme__
|
||||
// Row 1, Column 2
|
||||
|"https"
|
||||
|
||||
// Row 2, Column 1
|
||||
|__authority__
|
||||
// Row 2, Column 2
|
||||
|"www.example.com"
|
||||
|
||||
// Row 3, Column 1
|
||||
|__path__
|
||||
// Row 3, Column 2
|
||||
|"/path/to/file.txt"
|
||||
|
||||
// Row 4, Column 1
|
||||
|__query__
|
||||
// Row 4, Column 2
|
||||
|"userid=1001&pages=3&results=full"
|
||||
|
||||
// Row 5, Column 1
|
||||
|__fragment__
|
||||
// Row 5, Column 2
|
||||
|"page1"
|
||||
|
||||
|===
|
||||
|
||||
|
||||
The production rule for the example above is called a __URI__,
|
||||
which can contain all five parts. The specification using
|
||||
https://datatracker.ietf.org/doc/html/rfc2234[__ABNF__,window=blank_]
|
||||
https://datatracker.ietf.org/doc/html/rfc2234[__ABNF notation__,window=blank_]
|
||||
is:
|
||||
|
||||
|
||||
```
|
||||
URI = scheme ":" hier-part // [ "?" query ] // [ "#" fragment ]
|
||||
[source]
|
||||
----
|
||||
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
|
||||
|
||||
hier-part = "//" authority path-abempty
|
||||
/ path-absolute
|
||||
/ path-rootless
|
||||
/ path-empty
|
||||
```
|
||||
----
|
||||
|
||||
|
||||
In this notation, the square brackets ("\// [" and "\]") denote optional
|
||||
elements, quoted text represents character literals, and slashes are
|
||||
@@ -80,7 +95,7 @@ __URI-reference__. These are discussed in greater depth later.
|
||||
|
||||
|
||||
|
||||
=== Scheme
|
||||
== Scheme
|
||||
|
||||
The most important part is the __scheme__, whose production rule is:
|
||||
|
||||
@@ -98,28 +113,44 @@ https://en.wikipedia.org/wiki/Internet_Assigned_Numbers_Authority[Internet Assig
|
||||
Here are some registered schemes and their corresponding
|
||||
specifications:
|
||||
|
||||
// [table Public Schemes [
|
||||
// [Scheme]
|
||||
// [Specification]
|
||||
// ][
|
||||
// [[*http]]
|
||||
// [[@https://datatracker.ietf.org/doc/html/rfc7230#section-2.7.1 http URI Scheme (rfc7230)]]
|
||||
// ][
|
||||
// [[*magnet]]
|
||||
// [[@https://en.wikipedia.org/wiki/Magnet_URI_scheme Magnet URI scheme]]
|
||||
// ][
|
||||
// [[*mailto]]
|
||||
// [[@https://datatracker.ietf.org/doc/html/rfc6068 The 'mailto' URI Scheme (rfc6068)]]
|
||||
// ][
|
||||
// [[*payto]]
|
||||
// [[@https://datatracker.ietf.org/doc/html/rfc8905 The 'payto' URI Scheme for Payments (rfc8905)]]
|
||||
// ][
|
||||
// [[*telnet]]
|
||||
// [[@https://datatracker.ietf.org/doc/html/rfc4248 The telnet URI Scheme (rfc4248)]]
|
||||
// ][
|
||||
// [[*urn]]
|
||||
// [[@https://datatracker.ietf.org/doc/html/rfc2141 URN Syntax]]
|
||||
// ]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Scheme|Specification
|
||||
|
||||
// Row 1, Column 1
|
||||
|**http**
|
||||
// Row 1, Column 2
|
||||
|https://datatracker.ietf.org/doc/html/rfc7230#section-2.7.1[http URI Scheme (rfc7230),window=blank_]
|
||||
|
||||
// Row 2, Column 1
|
||||
|**magnet**
|
||||
// Row 2, Column 2
|
||||
|https://en.wikipedia.org/wiki/Magnet_URI_scheme[Magnet URI scheme,window=blank_]
|
||||
|
||||
// Row 3, Column 1
|
||||
|**mailto**
|
||||
// Row 3, Column 2
|
||||
|https://datatracker.ietf.org/doc/html/rfc6068[The 'mailto' URI Scheme (rfc6068),window=blank_]
|
||||
|
||||
// Row 4, Column 1
|
||||
|**payto**
|
||||
// Row 4, Column 2
|
||||
|https://datatracker.ietf.org/doc/html/rfc8905[The 'payto' URI Scheme for Payments (rfc8905),window=blank_]
|
||||
// Row 4, Column 4
|
||||
|
||||
// Row 5, Column 1
|
||||
|**telnet**
|
||||
// Row 5, Column 2
|
||||
|https://datatracker.ietf.org/doc/html/rfc4248[The telnet URI Scheme (rfc4248),window=blank_]
|
||||
|
||||
// Row 6, Column 1
|
||||
|**urn**
|
||||
// Row 6, Column 2
|
||||
|https://datatracker.ietf.org/doc/html/rfc2141[URN Syntax,window=blank_]
|
||||
|
||||
|===
|
||||
|
||||
|
||||
Private schemes are possible, defined by organizations to enumerate internal
|
||||
resources such as documents or physical devices, or to facilitate the operation
|
||||
@@ -130,19 +161,28 @@ that private does not imply secret; some private schemes such as Amazon's "s3"
|
||||
have publicly available specifications and are quite popular. Here are some
|
||||
examples:
|
||||
|
||||
// [table Private Schemes [
|
||||
// [Scheme]
|
||||
// [Specification]
|
||||
// ][
|
||||
// [[*app]]
|
||||
// [[@https://www.w3.org/TR/app-uri/ app: URL Scheme]]
|
||||
// ][
|
||||
// [[*odbc]]
|
||||
// [[@https://datatracker.ietf.org/doc/html/draft-patrick-lambert-odbc-uri-scheme ODBC URI Scheme]]
|
||||
// ][
|
||||
// [[*slack]]
|
||||
// [[@https://api.slack.com/reference/deep-linking Reference: Deep linking into Slack]]
|
||||
// ]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Scheme|Specification
|
||||
|
||||
// Row 1, Column 1
|
||||
|**app**
|
||||
// Row 1, Column 2
|
||||
|https://www.w3.org/TR/app-uri/[app: URL Scheme,window=blank_]
|
||||
|
||||
// Row 2, Column 1
|
||||
|**odbc**
|
||||
// Row 2, Column 2
|
||||
|https://datatracker.ietf.org/doc/html/draft-patrick-lambert-odbc-uri-scheme[ODBC URI Scheme,window=blank_]
|
||||
|
||||
// Row 3, Column 1
|
||||
|**slack**
|
||||
// Row 3, Column 2
|
||||
|https://api.slack.com/reference/deep-linking[Reference: Deep linking into Slack,window=blank_]
|
||||
|
||||
|===
|
||||
|
||||
|
||||
In some cases the scheme is implied by the surrounding context and
|
||||
therefore omitted. Here is a complete HTTP/1.1 GET request for the
|
||||
@@ -165,47 +205,66 @@ https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1[HTTP specification,w
|
||||
thusly:
|
||||
|
||||
|
||||
```
|
||||
origin-form = absolute-path // [ "?" query ]
|
||||
[source]
|
||||
----
|
||||
origin-form = absolute-path [ "?" query ]
|
||||
|
||||
absolute-path = 1*( "/" segment )
|
||||
```
|
||||
----
|
||||
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
All URLs have a scheme, whether it is explicit or implicit.
|
||||
The scheme determines what the rest of the URL means.
|
||||
====
|
||||
|
||||
// [note
|
||||
// All URLs have a scheme, whether it is explicit or implicit.
|
||||
// The scheme determines what the rest of the URL means.
|
||||
// ]
|
||||
|
||||
Here are some more examples of URLs using various schemes (and one example
|
||||
of something that is not a URL):
|
||||
|
||||
|
||||
// [table Scheme Examples [
|
||||
// [URL]
|
||||
// [Notes]
|
||||
// ][
|
||||
// [`https://www.boost.org/index.html`]
|
||||
// [Hierarchical URL with `https` protocol. Resource in the HTTP protocol.]
|
||||
// ][
|
||||
// [`ftp://host.dom/etc/motd`]
|
||||
// [Hierarchical URL with `ftp` scheme. Resource in the FTP protocol.]
|
||||
// ][
|
||||
// [`urn:isbn:045145052`]
|
||||
// [Opaque URL with `urn` scheme. Identifies `isbn` resource.]
|
||||
// ][
|
||||
// [`mailto:person@example.com`]
|
||||
// [Opaque URL with `mailto` scheme. Identifies e-mail address.]
|
||||
// ][
|
||||
// [`index.html`]
|
||||
// [URL reference. Missing scheme and authority.]
|
||||
// ][
|
||||
// [`www.boost.org`]
|
||||
// [A Protocol-Relative Link (PRL). [*Not a URL].]
|
||||
// ]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|URL|Notes
|
||||
|
||||
// Row 1, Column 1
|
||||
|`pass:[https://www.boost.org/index.html]`
|
||||
// Row 1, Column 2
|
||||
|Hierarchical URL with `https` protocol. Resource in the HTTP protocol.
|
||||
|
||||
// Row 2, Column 1
|
||||
|`pass:[ftp://host.dom/etc/motd]`
|
||||
// Row 2, Column 2
|
||||
|Hierarchical URL with `ftp` scheme. Resource in the FTP protocol.
|
||||
|
||||
// Row 3, Column 1
|
||||
|`urn:isbn:045145052`
|
||||
// Row 3, Column 2
|
||||
|Opaque URL with `urn` scheme. Identifies `isbn` resource.
|
||||
|
||||
// Row 4, Column 1
|
||||
|`mailto:person@example.com`
|
||||
// Row 4, Column 2
|
||||
|Opaque URL with `mailto` scheme. Identifies e-mail address.
|
||||
|
||||
// Row 5, Column 1
|
||||
|`index.html`
|
||||
// Row 5, Column 2
|
||||
|URL reference. Missing scheme and authority.
|
||||
|
||||
// Row 6, Column 1
|
||||
|`www.boost.org`
|
||||
// Row 6, Column 2
|
||||
|A Protocol-Relative Link (PRL). **Not**.
|
||||
|
||||
|===
|
||||
|
||||
|
||||
|
||||
=== Authority
|
||||
|
||||
== Authority
|
||||
|
||||
The authority determines how a resource can be accessed.
|
||||
It contains two parts: the
|
||||
@@ -218,9 +277,11 @@ which identify a communication endpoint having dominion
|
||||
over the resource described in the remainder of the URL.
|
||||
This is the ABNF specification for the authority part:
|
||||
|
||||
```
|
||||
authority = // [ user [ ":" password ] "@" ] host // [ ":" port ]
|
||||
```
|
||||
[source]
|
||||
----
|
||||
authority = [ user [ ":" password ] "@" ] host [ ":" port ]
|
||||
----
|
||||
|
||||
|
||||
The combination of user and optional password is called the
|
||||
__userinfo__.
|
||||
@@ -235,7 +296,7 @@ https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.3[__port__,window=blan
|
||||
which identify a communication endpoint having dominion
|
||||
over the resource described in the remainder of the URL.
|
||||
|
||||
// [$url/images/AuthorityDiagram.svg]
|
||||
image:AuthorityDiagram.svg[]
|
||||
|
||||
Some observations:
|
||||
|
||||
@@ -247,28 +308,42 @@ Some observations:
|
||||
The host subcomponent represents where resources
|
||||
are located.
|
||||
|
||||
// [note
|
||||
// Note that if an authority is present, the host is always
|
||||
// defined even if it is the empty string (corresponding
|
||||
// to a zero-length ['reg-name] in the BNF).
|
||||
//
|
||||
// [snippet_parsing_authority_10a]
|
||||
// ]
|
||||
[NOTE]
|
||||
====
|
||||
Note that if an authority is present, the host is always
|
||||
defined even if it is the empty string (corresponding
|
||||
to a zero-length __reg-name__ in the BNF).
|
||||
|
||||
// snippet_parsing_authority_10a
|
||||
[source,cpp]
|
||||
----
|
||||
url_view u( "https:///path/to_resource" );
|
||||
assert( u.has_authority() );
|
||||
assert( u.authority().buffer().empty() );
|
||||
assert( u.path() == "/path/to_resource" );
|
||||
----
|
||||
|
||||
====
|
||||
|
||||
|
||||
The authority component also influences how we should
|
||||
interpret the URL path. If the authority is present,
|
||||
the path component must either be empty or begin with
|
||||
a slash.
|
||||
|
||||
// [note Although the specification allows the format `username:password`,
|
||||
// the password component should be used with care.
|
||||
//
|
||||
// It is not recommended to transfer password data through URLs
|
||||
// unless this is an empty string indicating no password.]
|
||||
[NOTE]
|
||||
====
|
||||
Although the specification allows the format `username:password`,
|
||||
the password component should be used with care.
|
||||
|
||||
It is not recommended to transfer password data through URLs
|
||||
unless this is an empty string indicating no password.
|
||||
====
|
||||
|
||||
|
||||
|
||||
=== Containers
|
||||
|
||||
== Containers
|
||||
|
||||
This library provides the following containers, which
|
||||
are capable of storing any possible URL:
|
||||
@@ -299,14 +374,14 @@ use with URLs.
|
||||
// StringToken
|
||||
// Percent Encoding
|
||||
|
||||
// [include 3.1.parsing.qbk]
|
||||
// [include 3.2.containers.qbk]
|
||||
// [include 3.3.segments.qbk]
|
||||
// [include 3.4.params.qbk]
|
||||
// [include 3.5.normalization.qbk]
|
||||
// [include 3.6.stringtoken.qbk]
|
||||
// [include 3.7.percent-encoding.qbk]
|
||||
// [include 3.8.formatting.qbk]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//
|
||||
|
||||
|
||||
== Normalization
|
||||
= Normalization
|
||||
|
||||
Normalization allows us to determine if two URLs refer to the same
|
||||
resource. URLs comparisons serve the same purpose, where two strings
|
||||
@@ -40,20 +40,26 @@ of producing false negatives:
|
||||
Simple String Comparison can be performed by accessing the underlying
|
||||
buffer of URLs:
|
||||
|
||||
// snippet_normalizing_1
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_normalizing_1
|
||||
url_view u1("https://www.boost.org/index.html");
|
||||
url_view u2("https://www.boost.org/doc/../index.html");
|
||||
assert(u1.buffer() != u2.buffer());
|
||||
----
|
||||
|
||||
|
||||
By only considering the rules of `rfc3986`, Simple String
|
||||
By only considering the rules of https://tools.ietf.org/html/rfc3986[rfc3986,window=blank_], Simple String
|
||||
Comparison fails to identify the URLs above point to the same
|
||||
resource. The comparison operators implement Syntax-Based
|
||||
Normalization, which implements the rules defined by `rfc3986`.
|
||||
Normalization, which implements the rules defined by https://tools.ietf.org/html/rfc3986[rfc3986,window=blank_].
|
||||
|
||||
// snippet_normalizing_2
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_normalizing_2
|
||||
url_view u1("https://www.boost.org/index.html");
|
||||
url_view u2("https://www.boost.org/doc/../index.html");
|
||||
assert(u1 == u2);
|
||||
----
|
||||
|
||||
|
||||
@@ -66,13 +72,18 @@ same underlying representation. In other words, Simple String
|
||||
Comparison of two normalized URLs is equivalent to
|
||||
Syntax-Based Normalization.
|
||||
|
||||
// snippet_normalizing_3
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_normalizing_3
|
||||
url_view u1("https://www.boost.org/index.html");
|
||||
url u2("https://www.boost.org/doc/../index.html");
|
||||
assert(u1 == u2);
|
||||
u2.normalize();
|
||||
assert(u1.buffer() == u2.buffer());
|
||||
----
|
||||
|
||||
|
||||
Normalization uses the following definitions of `rfc3986`
|
||||
Normalization uses the following definitions of https://tools.ietf.org/html/rfc3986[rfc3986,window=blank_]
|
||||
to minimize false negatives:
|
||||
|
||||
* Case Normalization: percent-encoding triplets are normalized to use uppercase letters
|
||||
@@ -81,9 +92,12 @@ to minimize false negatives:
|
||||
|
||||
The following example normalizes the percent-encoding and path segments of a URL:
|
||||
|
||||
// snippet_normalizing_4
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_normalizing_4
|
||||
url u("https://www.boost.org/doc/../%69%6e%64%65%78%20file.html");
|
||||
u.normalize();
|
||||
assert(u.buffer() == "https://www.boost.org/index%20file.html");
|
||||
----
|
||||
|
||||
|
||||
@@ -92,9 +106,34 @@ for Scheme-Based and Protocol-Based Normalization. One common
|
||||
scheme-specific rule is ignoring the default port for that
|
||||
scheme and empty absolute paths:
|
||||
|
||||
// snippet_normalizing_5
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_normalizing_5
|
||||
auto normalize_http_url =
|
||||
[](url& u)
|
||||
{
|
||||
u.normalize();
|
||||
if (u.port() == "80" ||
|
||||
u.port().empty())
|
||||
u.remove_port();
|
||||
if (u.has_authority() &&
|
||||
u.encoded_path().empty())
|
||||
u.set_path_absolute(true);
|
||||
};
|
||||
|
||||
url u1("https://www.boost.org");
|
||||
normalize_http_url(u1);
|
||||
url u2("https://www.boost.org/");
|
||||
normalize_http_url(u2);
|
||||
url u3("https://www.boost.org:/");
|
||||
normalize_http_url(u3);
|
||||
url u4("https://www.boost.org:80/");
|
||||
normalize_http_url(u4);
|
||||
|
||||
assert(u1.buffer() == "https://www.boost.org/");
|
||||
assert(u2.buffer() == "https://www.boost.org/");
|
||||
assert(u3.buffer() == "https://www.boost.org/");
|
||||
assert(u4.buffer() == "https://www.boost.org/");
|
||||
----
|
||||
|
||||
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
|
||||
|
||||
|
||||
== Params
|
||||
= Params
|
||||
|
||||
While the query is specified as a plain string, it is usually
|
||||
interpreted as a set of key-value pairs commonly referred to as
|
||||
https://en.wikipedia.org/wiki/Query_string[__URL__,window=blank_],
|
||||
although here we use the term __query__ or __params__
|
||||
https://en.wikipedia.org/wiki/Query_string[__URL Parameters__,window=blank_],
|
||||
although here we use the term __query parameters__ or __params__
|
||||
for short. There is no official, standard specification of the
|
||||
query parameters format, but the W3C recommendations and HTML 5
|
||||
have this to say:
|
||||
@@ -45,35 +45,41 @@ Like the path, the library permits access to the params as
|
||||
using these separate, bidirectional view types which reference
|
||||
the underlying URL:
|
||||
|
||||
// [table Params Types [
|
||||
// [Type]
|
||||
// [Accessor]
|
||||
// [Description]
|
||||
// ][
|
||||
// [__params_view__]
|
||||
// [[link url.ref.boost__urls__url_view_base.params `params`]]
|
||||
// [
|
||||
// A read-only range of decoded params.
|
||||
// ]
|
||||
// ][
|
||||
// [__params_ref__]
|
||||
// [[link url.ref.boost__urls__url_base.params `params`]]
|
||||
// [
|
||||
// A modifiable range of decoded params.
|
||||
// ]
|
||||
// ][
|
||||
// [__params_encoded_view__]
|
||||
// [[link url.ref.boost__urls__url_view_base.encoded_params `encoded_params`]]
|
||||
// [
|
||||
// A read-only range of params.
|
||||
// ]
|
||||
// ][
|
||||
// [__params_encoded_ref__]
|
||||
// [[link url.ref.boost__urls__url_base.encoded_params `encoded_params`]]
|
||||
// [
|
||||
// A modifiable range of params.
|
||||
// ]
|
||||
// ]]
|
||||
[cols="a,a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Type|Accessor|Description
|
||||
|
||||
// Row 1, Column 1
|
||||
|`params_view`
|
||||
// Row 1, Column 2
|
||||
|`params`
|
||||
// Row 1, Column 3
|
||||
|A read-only range of decoded params.
|
||||
|
||||
// Row 2, Column 1
|
||||
|`params_ref`
|
||||
// Row 2, Column 2
|
||||
|`params`
|
||||
// Row 2, Column 3
|
||||
|A modifiable range of decoded params.
|
||||
|
||||
// Row 3, Column 1
|
||||
|`params_encoded_view`
|
||||
// Row 3, Column 2
|
||||
|`encoded_params`
|
||||
// Row 3, Column 3
|
||||
|A read-only range of params.
|
||||
|
||||
// Row 4, Column 1
|
||||
|`params_encoded_ref`
|
||||
// Row 4, Column 2
|
||||
|`encoded_params`
|
||||
// Row 4, Column 3
|
||||
|A modifiable range of params.
|
||||
|
||||
|===
|
||||
|
||||
|
||||
A param always has a key, even if it is the empty string.
|
||||
The value is optional; an empty string is distinct from
|
||||
@@ -81,34 +87,39 @@ no value. To represent individual params the library uses
|
||||
these types, distinguished by their ownership model and
|
||||
whether or not percent-escapes are possible:
|
||||
|
||||
// [table Param Types [
|
||||
// [Type]
|
||||
// [String Type]
|
||||
// [Description]
|
||||
// ][
|
||||
// [__param__]
|
||||
// [__std_string__]
|
||||
// [
|
||||
// A key-value pair with ownership of the strings.
|
||||
// This can be used to hold decoded strings, or to
|
||||
// allow the caller to take ownership of a param
|
||||
// by making a copy.
|
||||
// ]
|
||||
// ][
|
||||
// [__param_view__]
|
||||
// [__string_view__]
|
||||
// [
|
||||
// A key-value pair without percent-escapes,
|
||||
// referencing externally managed character buffers.
|
||||
// ]
|
||||
// ][
|
||||
// [__param_pct_view__]
|
||||
// [__pct_string_view__]
|
||||
// [
|
||||
// A key-value pair which may contain percent-escapes,
|
||||
// referencing externally managed character buffers.
|
||||
// ]
|
||||
// ]]
|
||||
[cols="a,a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Type|String Type|Description
|
||||
|
||||
// Row 1, Column 1
|
||||
|`param`
|
||||
// Row 1, Column 2
|
||||
|https://en.cppreference.com/w/cpp/string/basic_string[`std::string`,window=blank_]
|
||||
// Row 1, Column 3
|
||||
|A key-value pair with ownership of the strings.
|
||||
This can be used to hold decoded strings, or to
|
||||
allow the caller to take ownership of a param
|
||||
by making a copy.
|
||||
|
||||
// Row 2, Column 1
|
||||
|`param_view`
|
||||
// Row 2, Column 2
|
||||
|`string_view`
|
||||
// Row 2, Column 3
|
||||
|A key-value pair without percent-escapes,
|
||||
referencing externally managed character buffers.
|
||||
|
||||
// Row 3, Column 1
|
||||
|`param_pct_view`
|
||||
// Row 3, Column 2
|
||||
|`pct_string_view`
|
||||
// Row 3, Column 3
|
||||
|A key-value pair which may contain percent-escapes,
|
||||
referencing externally managed character buffers.
|
||||
|
||||
|===
|
||||
|
||||
|
||||
Param types can be constructed from initializer lists,
|
||||
allowing for convenient notation. To represent a missing
|
||||
@@ -118,32 +129,49 @@ or `nullptr` may be used. This table shows some examples
|
||||
of initializer lists used to construct a param type, and
|
||||
the resulting data members:
|
||||
|
||||
// [table Param Initializers [
|
||||
// [Statement]
|
||||
// [`qp.key`]
|
||||
// [`qp.value`]
|
||||
// [`qp.has_value`]
|
||||
// ][
|
||||
// [`param qp = { "first", "John" };`]
|
||||
// [`"First"`]
|
||||
// [`"John"`]
|
||||
// [`true`]
|
||||
// ][
|
||||
// [`param qp = { "first", "" };`]
|
||||
// [`"First"`]
|
||||
// [`""`]
|
||||
// [`true`]
|
||||
// ][
|
||||
// [`param qp = { "first", no_value };`]
|
||||
// [`"First"`]
|
||||
// [`""`]
|
||||
// [`false`]
|
||||
// ][
|
||||
// [`param qp = { "", "Doe" };`]
|
||||
// [`""`]
|
||||
// [`"Doe"`]
|
||||
// [`true`]
|
||||
// ]]
|
||||
[cols="a,a,a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Statement|`qp.key`|`qp.value`|`qp.has_value`
|
||||
|
||||
// Row 1, Column 1
|
||||
|`param qp = { "first", "John" };`
|
||||
// Row 1, Column 2
|
||||
|`"First"`
|
||||
// Row 1, Column 3
|
||||
|`"John"`
|
||||
// Row 1, Column 4
|
||||
|`true`
|
||||
|
||||
// Row 2, Column 1
|
||||
|`param qp = { "first", "" };`
|
||||
// Row 2, Column 2
|
||||
|`"First"`
|
||||
// Row 2, Column 3
|
||||
|`""`
|
||||
// Row 2, Column 4
|
||||
|`true`
|
||||
|
||||
// Row 3, Column 1
|
||||
|`param qp = { "first", no_value };`
|
||||
// Row 3, Column 2
|
||||
|`"First"`
|
||||
// Row 3, Column 3
|
||||
|`""`
|
||||
// Row 3, Column 4
|
||||
|`false`
|
||||
|
||||
// Row 4, Column 1
|
||||
|`param qp = { "", "Doe" };`
|
||||
// Row 4, Column 2
|
||||
|`""`
|
||||
// Row 4, Column 3
|
||||
|`"Doe"`
|
||||
// Row 4, Column 4
|
||||
|`true`
|
||||
|
||||
|===
|
||||
|
||||
|
||||
To understand the relationship between the query and the
|
||||
resulting range of params, first we define this
|
||||
@@ -151,9 +179,17 @@ function `parms` which returns a list of params
|
||||
corresponding to the elements in a container
|
||||
of params:
|
||||
|
||||
// code_container_5_1
|
||||
[source,cpp]
|
||||
----
|
||||
// code_container_5_1
|
||||
auto parms( core::string_view s ) -> std::list< param >
|
||||
{
|
||||
url_view u( s );
|
||||
std::list< param > seq;
|
||||
for( auto qp : u.params() )
|
||||
seq.push_back( qp );
|
||||
return seq;
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
@@ -161,28 +197,43 @@ In the table below we show the result of invoking `parms` with
|
||||
different queries. This demonstrates how the syntax of the query
|
||||
maps to the parameter structure:
|
||||
|
||||
// [table Params Sequences [
|
||||
// [s]
|
||||
// [`parms( s )`]
|
||||
// ][
|
||||
// [`"?first=John&last=Doe"`]
|
||||
// [`{ { "first", "John" }, { "last", "Doe" } }`]
|
||||
// ][
|
||||
// [`"?id=42&unsorted"`]
|
||||
// [`{ { "id", "42" }, { "last", no_value } }`]
|
||||
// ][
|
||||
// [`"?col=cust&row="`]
|
||||
// [`{ { "col", "cust" }, { "row", "" } }`]
|
||||
// ][
|
||||
// [`"?justify=left&"`]
|
||||
// [`{ { "justify", "left" }, { "", no_value } }`]
|
||||
// ][
|
||||
// [`"?"`]
|
||||
// [`{ { "", no_value } }`]
|
||||
// ][
|
||||
// [`""`]
|
||||
// [`{ }`]
|
||||
// ]]
|
||||
[cols="a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|s|`parms( s )`
|
||||
|
||||
// Row 1, Column 1
|
||||
|`"?first=John&last=Doe"`
|
||||
// Row 1, Column 2
|
||||
|`{ { "first", "John" }, { "last", "Doe" } }`
|
||||
|
||||
// Row 2, Column 1
|
||||
|`"?id=42&unsorted"`
|
||||
// Row 2, Column 2
|
||||
|`{ { "id", "42" }, { "last", no_value } }`
|
||||
|
||||
// Row 3, Column 1
|
||||
|`"?col=cust&row="`
|
||||
// Row 3, Column 2
|
||||
|`{ { "col", "cust" }, { "row", "" } }`
|
||||
|
||||
// Row 4, Column 1
|
||||
|`"?justify=left&"`
|
||||
// Row 4, Column 2
|
||||
|`{ { "justify", "left" }, { "", no_value } }`
|
||||
|
||||
// Row 5, Column 1
|
||||
|`"?"`
|
||||
// Row 5, Column 2
|
||||
|`{ { "", no_value } }`
|
||||
|
||||
// Row 6, Column 1
|
||||
|`""`
|
||||
// Row 6, Column 2
|
||||
|`{ }`
|
||||
|
||||
|===
|
||||
|
||||
|
||||
It may be surprising that an empty query string ("?")
|
||||
produces a sequence with one empty param. This is by
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//
|
||||
|
||||
|
||||
== Parsing
|
||||
= Parsing
|
||||
|
||||
Algorithms which parse URLs return a view which references the
|
||||
underlying character buffer without taking ownership, avoiding
|
||||
@@ -17,9 +17,10 @@ string literal containing a
|
||||
https://datatracker.ietf.org/doc/html/rfc3986#section-3[__URI__,window=blank_]:
|
||||
|
||||
|
||||
// code_urls_parsing_1
|
||||
[source,cpp]
|
||||
----
|
||||
// code_urls_parsing_1
|
||||
boost::core::string_view s = "https://user:pass@example.com:443/path/to/my%2dfile.txt?id=42&name=John%20Doe+Jingleheimer%2DSchmidt#page%20anchor";
|
||||
----
|
||||
|
||||
|
||||
@@ -42,9 +43,10 @@ https://datatracker.ietf.org/doc/html/rfc3986#section-4.1[__URI-reference__,wind
|
||||
grammar, throwing an exception upon failure. The following two statements
|
||||
are equivalent:
|
||||
|
||||
// code_urls_parsing_2
|
||||
[source,cpp]
|
||||
----
|
||||
// code_urls_parsing_2
|
||||
boost::system::result<url_view> r = parse_uri( s );
|
||||
----
|
||||
|
||||
|
||||
@@ -54,49 +56,73 @@ There are several varieties of URLs, and depending on the use-case a
|
||||
particular grammar may be needed. In the target of an HTTP GET request
|
||||
for example, the scheme and fragment are omitted. This corresponds to the
|
||||
https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1[__origin-form__,window=blank_]
|
||||
production rule described in `rfc7230`. The function
|
||||
production rule described in https://tools.ietf.org/html/rfc7230[rfc7230,window=blank_]. The function
|
||||
`parse_origin_form`
|
||||
is suited for this purpose. All the URL parsing functions are listed here:
|
||||
|
||||
// [table Parsing Functions [
|
||||
// [Function]
|
||||
// [Grammar]
|
||||
// [Example]
|
||||
// [Notes]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__parse_absolute_uri `parse_absolute_uri`]]
|
||||
// [[@https://datatracker.ietf.org/doc/html/rfc3986#section-4.3 ['absolute-URI]]]
|
||||
// [[teletype]`http://www.boost.org/index.html?field=value`]
|
||||
// [No fragment]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__parse_origin_form `parse_origin_form`]]
|
||||
// [[@https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1 ['origin-form]]]
|
||||
// [[teletype]`/index.html?field=value`]
|
||||
// [Used in HTTP]
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__parse_relative_ref `parse_relative_ref`]]
|
||||
// [[@https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 ['relative-ref]]]
|
||||
// [[teletype]`//www.boost.org/index.html?field=value#downloads`]
|
||||
// []
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__parse_uri `parse_uri`]]
|
||||
// [[@https://datatracker.ietf.org/doc/html/rfc3986#section-3 ['URI]]]
|
||||
// [[teletype]`http://www.boost.org/index.html?field=value#downloads`]
|
||||
// []
|
||||
// ][
|
||||
// [[link url.ref.boost__urls__parse_uri_reference `parse_uri_reference`]]
|
||||
// [[@https://datatracker.ietf.org/doc/html/rfc3986#section-4.1 ['URI-reference]]]
|
||||
// [[teletype]`http://www.boost.org/index.html`]
|
||||
// [Any ['URI] or ['relative-ref]]
|
||||
// ]]
|
||||
[cols="a,a,a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Function|Grammar|Example|Notes
|
||||
|
||||
// Row 1, Column 1
|
||||
|`parse_absolute_uri`
|
||||
// Row 1, Column 2
|
||||
|https://datatracker.ietf.org/doc/html/rfc3986#section-4.3[__absolute-URI__,window=blank_]
|
||||
// Row 1, Column 3
|
||||
|`pass:[http://www.boost.org/index.html?field=value]`
|
||||
// Row 1, Column 4
|
||||
|No fragment
|
||||
|
||||
// Row 2, Column 1
|
||||
|`parse_origin_form`
|
||||
// Row 2, Column 2
|
||||
|https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1[__origin-form__,window=blank_]
|
||||
// Row 2, Column 3
|
||||
|`pass:[/index.html?field=value]`
|
||||
// Row 2, Column 4
|
||||
|Used in HTTP
|
||||
|
||||
// Row 3, Column 1
|
||||
|`parse_relative_ref`
|
||||
// Row 3, Column 2
|
||||
|https://datatracker.ietf.org/doc/html/rfc3986#section-4.2[__relative-ref__,window=blank_]
|
||||
// Row 3, Column 3
|
||||
|`pass:[//www.boost.org/index.html?field=value#downloads]`
|
||||
// Row 3, Column 4
|
||||
|
|
||||
|
||||
// Row 4, Column 1
|
||||
|`parse_uri`
|
||||
// Row 4, Column 2
|
||||
|https://datatracker.ietf.org/doc/html/rfc3986#section-3[__URI__,window=blank_]
|
||||
// Row 4, Column 3
|
||||
|`pass:[http://www.boost.org/index.html?field=value#downloads]`
|
||||
// Row 4, Column 4
|
||||
|
|
||||
|
||||
// Row 5, Column 1
|
||||
|`parse_uri_reference`
|
||||
// Row 5, Column 2
|
||||
|https://datatracker.ietf.org/doc/html/rfc3986#section-4.1[__URI-reference__,window=blank_]
|
||||
// Row 5, Column 3
|
||||
|`pass:[http://www.boost.org/index.html]`
|
||||
// Row 5, Column 4
|
||||
|Any __URI__ or __relative-ref__
|
||||
|
||||
|===
|
||||
|
||||
|
||||
The URL is stored in its serialized form. Therefore, it can
|
||||
always be easily output, sent, or embedded as part of a
|
||||
protocol:
|
||||
|
||||
// snippet_parsing_url_1bb
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_parsing_url_1bb
|
||||
url u = parse_uri_reference( "https://www.example.com/path/to/file.txt" ).value();
|
||||
|
||||
assert(u.encoded_path() == "/path/to/file.txt");
|
||||
----
|
||||
|
||||
|
||||
@@ -104,9 +130,12 @@ A `url` is an allocating container which owns its character buffer.
|
||||
Upon construction from `url_view`, it allocates dynamic storage
|
||||
to hold a copy of the string.
|
||||
|
||||
// snippet_parsing_url_1bc
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_parsing_url_1bc
|
||||
boost::system::result< url > rv = parse_uri_reference( "https://www.example.com/path/to/file.txt" );
|
||||
|
||||
static_assert( std::is_convertible< boost::system::result< url_view >, boost::system::result< url > >::value, "" );
|
||||
----
|
||||
|
||||
|
||||
@@ -114,13 +143,16 @@ A `static_url` is a container which owns its character buffer for
|
||||
a URL whose maximum size is known. Upon construction from
|
||||
`url_view`, it does not perform any dynamic memory allocations.
|
||||
|
||||
// snippet_parsing_url_1bd
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_parsing_url_1bd
|
||||
boost::system::result< static_url<1024> > rv = parse_uri_reference( "https://www.example.com/path/to/file.txt" );
|
||||
|
||||
static_assert( std::is_convertible< boost::system::result< static_url<1024> >, boost::system::result< url > >::value, "" );
|
||||
----
|
||||
|
||||
|
||||
=== Result Type
|
||||
== Result Type
|
||||
|
||||
These functions have a return type which uses the `result` alias
|
||||
template. This class allows the parsing algorithms to report
|
||||
@@ -129,9 +161,20 @@ errors without referring to exceptions.
|
||||
The functions `result::operator bool()` and `result::operator*`
|
||||
can be used to check if the result contains an error.
|
||||
|
||||
// snippet_parsing_url_1
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_parsing_url_1
|
||||
boost::system::result< url > ru = parse_uri_reference( "https://www.example.com/path/to/file.txt" );
|
||||
if ( ru )
|
||||
{
|
||||
url u = *ru;
|
||||
assert(u.encoded_path() == "/path/to/file.txt");
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::system::error_code e = ru.error();
|
||||
handle_error(e);
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
@@ -140,9 +183,18 @@ error, `result::operator*` provides an unchecked alternative to get a value
|
||||
from `result`. In contexts where it is acceptable to throw errors,
|
||||
`result::value` can be used directly.
|
||||
|
||||
// snippet_parsing_url_1b
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_parsing_url_1b
|
||||
try
|
||||
{
|
||||
url u = parse_uri_reference( "https://www.example.com/path/to/file.txt" ).value();
|
||||
assert(u.encoded_path() == "/path/to/file.txt");
|
||||
}
|
||||
catch (boost::system::system_error &e)
|
||||
{
|
||||
handle_error(e);
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
|
||||
@@ -8,61 +8,83 @@
|
||||
//
|
||||
|
||||
|
||||
== Percent Encoding
|
||||
= Percent Encoding
|
||||
|
||||
=== Encoding
|
||||
== Encoding
|
||||
|
||||
The `encode` can be used to percent-encode strings
|
||||
with the specified `CharSet`.
|
||||
with the specified __CharSet__.
|
||||
|
||||
// snippet_encoding_1
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_1
|
||||
std::string s = encode("hello world!", unreserved_chars);
|
||||
assert(s == "hello%20world%21");
|
||||
----
|
||||
|
||||
|
||||
A few parameters, such as encoding spaces as plus (`+`), can be adjusted
|
||||
with `encode_opts`:
|
||||
|
||||
// snippet_encoding_2
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_2
|
||||
encoding_opts opt;
|
||||
opt.space_as_plus = true;
|
||||
std::string s = encode("msg=hello world", pchars, opt);
|
||||
assert(s == "msg=hello+world");
|
||||
----
|
||||
|
||||
|
||||
The result type of the function can also be specified via a `StringToken`
|
||||
The result type of the function can also be specified via a __StringToken__
|
||||
so that strings can be reused or appended.
|
||||
|
||||
// snippet_encoding_3
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_3
|
||||
std::string s;
|
||||
encode("hello ", pchars, {}, string_token::assign_to(s));
|
||||
encode("world", pchars, {}, string_token::append_to(s));
|
||||
assert(s == "hello%20world");
|
||||
----
|
||||
|
||||
|
||||
We can also use `encoded_size` to
|
||||
determine the required size before attempting to encode:
|
||||
|
||||
// snippet_encoding_4
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_4
|
||||
boost::core::string_view e = "hello world";
|
||||
std::string s;
|
||||
s.reserve(encoded_size(e, pchars));
|
||||
encode(e, pchars, {}, string_token::assign_to(s));
|
||||
assert(s == "hello%20world");
|
||||
----
|
||||
|
||||
|
||||
In other scenarios, strings can also be directly encoded into buffers:
|
||||
|
||||
// snippet_encoding_5
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_5
|
||||
boost::core::string_view e = "hello world";
|
||||
std::string s;
|
||||
s.resize(encoded_size(e, pchars));
|
||||
encode(&s[0], s.size(), e, pchars);
|
||||
assert(s == "hello%20world");
|
||||
----
|
||||
|
||||
|
||||
=== Validating
|
||||
== Validating
|
||||
|
||||
The class `pct_string_view` represents a reference percent-encoded strings:
|
||||
|
||||
// snippet_encoding_6
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_6
|
||||
pct_string_view sv = "hello%20world";
|
||||
assert(sv == "hello%20world");
|
||||
----
|
||||
|
||||
|
||||
@@ -75,9 +97,14 @@ To simply validate a string without recurring to exceptions, a `result`
|
||||
can be returned with the
|
||||
`make_pct_string_view`:
|
||||
|
||||
// snippet_encoding_7
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_7
|
||||
boost::system::result<pct_string_view> rs =
|
||||
make_pct_string_view("hello%20world");
|
||||
assert(rs.has_value());
|
||||
pct_string_view sv = rs.value();
|
||||
assert(sv == "hello%20world");
|
||||
----
|
||||
|
||||
|
||||
@@ -88,9 +115,13 @@ The modifying functions in classes such as `url` expect instances of
|
||||
removes the responsibility of revalidating this information or throwing
|
||||
exceptions from these functions:
|
||||
|
||||
// snippet_encoding_8
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_8
|
||||
pct_string_view s = "path/to/file";
|
||||
url u;
|
||||
u.set_encoded_path(s);
|
||||
assert(u.buffer() == "path/to/file");
|
||||
----
|
||||
|
||||
|
||||
@@ -98,9 +129,12 @@ When exceptions are acceptable, a common pattern is to let a literal string
|
||||
or other type convertible to `string_view` be implicitly converted to
|
||||
`pct_string_view`.
|
||||
|
||||
// snippet_encoding_9
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_9
|
||||
url u;
|
||||
u.set_encoded_path("path/to/file");
|
||||
assert(u.buffer() == "path/to/file");
|
||||
----
|
||||
|
||||
|
||||
@@ -112,9 +146,13 @@ Reusing the validation guarantee is particularly useful when the
|
||||
`pct_string_view` comes from another source where the data is also
|
||||
ensured to be validated:
|
||||
|
||||
// snippet_encoding_10
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_10
|
||||
url_view uv("path/to/file");
|
||||
url u;
|
||||
u.set_encoded_path(uv.encoded_path());
|
||||
assert(u.buffer() == "path/to/file");
|
||||
----
|
||||
|
||||
|
||||
@@ -124,15 +162,20 @@ does not to revalidate any information from
|
||||
`encoded_path`
|
||||
because these references are passed as `pct_string_view`.
|
||||
|
||||
=== Decode
|
||||
== Decode
|
||||
|
||||
The class `pct_string_view` represents a reference percent-encoded strings.
|
||||
`decode_view` is analogous to `pct_string_view`, with the main difference
|
||||
that the underlying buffer always dereferences to decoded characters.
|
||||
|
||||
// snippet_encoding_11
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_11
|
||||
pct_string_view es("hello%20world");
|
||||
assert(es == "hello%20world");
|
||||
|
||||
decode_view dv("hello%20world");
|
||||
assert(dv == "hello world");
|
||||
----
|
||||
|
||||
|
||||
@@ -140,9 +183,15 @@ A `decode_view` can also be created from a `pct_string_view` with the
|
||||
`operator*`.
|
||||
The also gives us an opportunity to validate external strings:
|
||||
|
||||
// snippet_encoding_12
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_12
|
||||
boost::system::result<pct_string_view> rs =
|
||||
make_pct_string_view("hello%20world");
|
||||
assert(rs.has_value());
|
||||
pct_string_view s = rs.value();
|
||||
decode_view dv = *s;
|
||||
assert(dv == "hello world");
|
||||
----
|
||||
|
||||
|
||||
@@ -150,9 +199,37 @@ This is particularly useful when the decoded string need to be accessed
|
||||
for comparisons with no necessity to explicitly decoding the
|
||||
string into a buffer:
|
||||
|
||||
// snippet_encoding_13
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_13
|
||||
url_view u =
|
||||
parse_relative_ref("user/john%20doe/profile%20photo.jpg").value();
|
||||
std::vector<std::string> route =
|
||||
{"user", "john doe", "profile photo.jpg"};
|
||||
auto segs = u.encoded_segments();
|
||||
auto it0 = segs.begin();
|
||||
auto end0 = segs.end();
|
||||
auto it1 = route.begin();
|
||||
auto end1 = route.end();
|
||||
while (
|
||||
it0 != end0 &&
|
||||
it1 != end1)
|
||||
{
|
||||
pct_string_view seg0 = *it0;
|
||||
decode_view dseg0 = *seg0;
|
||||
boost::core::string_view seg1 = *it1;
|
||||
if (dseg0 == seg1)
|
||||
{
|
||||
++it0;
|
||||
++it1;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool route_match = it0 == end0 && it1 == end1;
|
||||
assert(route_match);
|
||||
----
|
||||
|
||||
|
||||
@@ -162,9 +239,14 @@ can be used to decode the data into a buffer. Like the free-function
|
||||
`encode`, decoding options and the string
|
||||
token can be customized.
|
||||
|
||||
// snippet_encoding_14
|
||||
[source,cpp]
|
||||
----
|
||||
// snippet_encoding_14
|
||||
pct_string_view s = "user/john%20doe/profile%20photo.jpg";
|
||||
std::string buf;
|
||||
buf.resize(s.decoded_size());
|
||||
s.decode({}, string_token::assign_to(buf));
|
||||
assert(buf == "user/john doe/profile photo.jpg");
|
||||
----
|
||||
|
||||
|
||||
|
||||
@@ -10,42 +10,48 @@
|
||||
|
||||
|
||||
|
||||
== Segments
|
||||
= Segments
|
||||
|
||||
Hierarchical schemes often interpret the path as a slash-delimited
|
||||
sequence of percent-encoded strings called segments.
|
||||
In this library the segments may be accessed using these separate,
|
||||
bidirectional view types which reference the underlying URL:
|
||||
|
||||
// [table Segments Types [
|
||||
// [Type]
|
||||
// [Accessor]
|
||||
// [Description]
|
||||
// ][
|
||||
// [__segments_view__]
|
||||
// [[link url.ref.boost__urls__url_view_base.segments `segments`]]
|
||||
// [
|
||||
// A read-only range of decoded segments.
|
||||
// ]
|
||||
// ][
|
||||
// [__segments_ref__]
|
||||
// [[link url.ref.boost__urls__url_base.segments `segments`]]
|
||||
// [
|
||||
// A modifiable range of decoded segments.
|
||||
// ]
|
||||
// ][
|
||||
// [__segments_encoded_view__]
|
||||
// [[link url.ref.boost__urls__url_view_base.encoded_segments `encoded_segments`]]
|
||||
// [
|
||||
// A read-only range of segments.
|
||||
// ]
|
||||
// ][
|
||||
// [__segments_encoded_ref__]
|
||||
// [[link url.ref.boost__urls__url_base.encoded_segments `encoded_segments`]]
|
||||
// [
|
||||
// A modifiable range of segments.
|
||||
// ]
|
||||
// ]]
|
||||
[cols="a,a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|Type|Accessor|Description
|
||||
|
||||
// Row 1, Column 1
|
||||
|`segments_view`
|
||||
// Row 1, Column 2
|
||||
|`segments`
|
||||
// Row 1, Column 3
|
||||
|A read-only range of decoded segments.
|
||||
|
||||
// Row 2, Column 1
|
||||
|`segments_ref`
|
||||
// Row 2, Column 2
|
||||
|`segments`
|
||||
// Row 2, Column 3
|
||||
|A modifiable range of decoded segments.
|
||||
|
||||
// Row 3, Column 1
|
||||
|`segments_encoded_view`
|
||||
// Row 3, Column 2
|
||||
|`encoded_segments`
|
||||
// Row 3, Column 3
|
||||
|A read-only range of segments.
|
||||
|
||||
// Row 4, Column 1
|
||||
|`segments_encoded_ref`
|
||||
// Row 4, Column 2
|
||||
|`encoded_segments`
|
||||
// Row 4, Column 3
|
||||
|A modifiable range of segments.
|
||||
|
||||
|===
|
||||
|
||||
|
||||
First we observe these invariants about paths and segments:
|
||||
|
||||
@@ -73,9 +79,17 @@ we define this function `segs` which returns a list of
|
||||
strings corresponding to the elements in a container of segments:
|
||||
|
||||
|
||||
// code_container_4_1
|
||||
[source,cpp]
|
||||
----
|
||||
// code_container_4_1
|
||||
auto segs( core::string_view s ) -> std::list< std::string >
|
||||
{
|
||||
url_view u( s );
|
||||
std::list< std::string > seq;
|
||||
for( auto seg : u.encoded_segments() )
|
||||
seq.push_back( seg.decode() );
|
||||
return seq;
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
@@ -83,59 +97,97 @@ In this table we show the result of invoking `segs` with
|
||||
different paths. This demonstrates how the library achieves
|
||||
the invariants described above for various interesting cases:
|
||||
|
||||
// [table Segments [
|
||||
// [s]
|
||||
// [`segs( s )`]
|
||||
// [absolute]
|
||||
// ][
|
||||
// [`""`]
|
||||
// [`{ }`]
|
||||
// []
|
||||
// ][
|
||||
// [`"/"`]
|
||||
// [`{ }`]
|
||||
// [yes]
|
||||
// ][
|
||||
// [`"./"`]
|
||||
// [`{ "" }`]
|
||||
// []
|
||||
// ][
|
||||
// [`"usr"`]
|
||||
// [`{ "usr" }`]
|
||||
// []
|
||||
// ][
|
||||
// [`"./usr"`]
|
||||
// [`{ "usr" }`]
|
||||
// []
|
||||
// ][
|
||||
// [`"/index.htm"`]
|
||||
// [`{ "index.htm" }`]
|
||||
// [yes]
|
||||
// ][
|
||||
// [`"/images/cat-pic.gif"`]
|
||||
// [`{ "images", "cat-pic.gif" }`]
|
||||
// [yes]
|
||||
// ][
|
||||
// [`"images/cat-pic.gif"`]
|
||||
// [`{ "images", "cat-pic.gif" }`]
|
||||
// []
|
||||
// ][
|
||||
// [`"/fast//query"`]
|
||||
// [`{ "fast", "", "query" }`]
|
||||
// [yes]
|
||||
// ][
|
||||
// [`"fast//"`]
|
||||
// [`{ "fast", "", "" }`]
|
||||
// []
|
||||
// ][
|
||||
// [`"/./"`]
|
||||
// [`{ "" }`]
|
||||
// [yes]
|
||||
// ][
|
||||
// [`".//"`]
|
||||
// [`{ "", "" }`]
|
||||
// []
|
||||
// ]]
|
||||
[cols="a,a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|s|`segs( s )`|absolute
|
||||
|
||||
// Row 1, Column 1
|
||||
|`""`
|
||||
// Row 1, Column 2
|
||||
|`{ }`
|
||||
// Row 1, Column 3
|
||||
|
|
||||
|
||||
// Row 2, Column 1
|
||||
|`"/"`
|
||||
// Row 2, Column 2
|
||||
|`{ }`
|
||||
// Row 2, Column 3
|
||||
|yes
|
||||
|
||||
// Row 3, Column 1
|
||||
|`"./"`
|
||||
// Row 3, Column 2
|
||||
|`{ "" }`
|
||||
// Row 3, Column 3
|
||||
|
|
||||
|
||||
// Row 4, Column 1
|
||||
|`"usr"`
|
||||
// Row 4, Column 2
|
||||
|`{ "usr" }`
|
||||
// Row 4, Column 3
|
||||
|
|
||||
|
||||
// Row 5, Column 1
|
||||
|`"./usr"`
|
||||
// Row 5, Column 2
|
||||
|`{ "usr" }`
|
||||
// Row 5, Column 3
|
||||
|
|
||||
|
||||
// Row 6, Column 1
|
||||
|`"/index.htm"`
|
||||
// Row 6, Column 2
|
||||
|`{ "index.htm" }`
|
||||
// Row 6, Column 3
|
||||
|yes
|
||||
|
||||
// Row 7, Column 1
|
||||
|`"/images/cat-pic.gif"`
|
||||
// Row 7, Column 2
|
||||
|`{ "images", "cat-pic.gif" }`
|
||||
// Row 7, Column 3
|
||||
|yes
|
||||
|
||||
// Row 8, Column 1
|
||||
|`"images/cat-pic.gif"`
|
||||
// Row 8, Column 2
|
||||
|`{ "images", "cat-pic.gif" }`
|
||||
// Row 8, Column 3
|
||||
|
|
||||
|
||||
// Row 9, Column 1
|
||||
|`"/fast//query"`
|
||||
// Row 9, Column 2
|
||||
|`{ "fast", "", "query" }`
|
||||
// Row 9, Column 3
|
||||
|yes
|
||||
|
||||
// Row 10, Column 1
|
||||
|`"fast//"`
|
||||
// Row 10, Column 2
|
||||
|`{ "fast", "", "" }`
|
||||
// Row 10, Column 3
|
||||
|
|
||||
|
||||
// Row 11, Column 1
|
||||
|`"/./"`
|
||||
// Row 11, Column 2
|
||||
|`{ "" }`
|
||||
// Row 11, Column 3
|
||||
|yes
|
||||
|
||||
// Row 12, Column 1
|
||||
|`".//"`
|
||||
// Row 12, Column 2
|
||||
|`{ "", "" }`
|
||||
// Row 12, Column 3
|
||||
|
|
||||
|
||||
|===
|
||||
|
||||
|
||||
This implies that two paths may map to the same sequence of
|
||||
segments . In the paths `"usr"` and `"./usr"`, the `"./"`
|
||||
@@ -212,59 +264,97 @@ various modifications to a URL containing a path:
|
||||
// set_encoded_path()
|
||||
// edit_segments()
|
||||
|
||||
// [table Path Operations [
|
||||
// [URL]
|
||||
// [Operation]
|
||||
// [Result]
|
||||
// ][
|
||||
// [`"info:kyle:xy"`]
|
||||
// [`remove_scheme()`]
|
||||
// [`"kyle%3Axy"`]
|
||||
// ][
|
||||
// [`"kyle%3Axy"`]
|
||||
// [`set_scheme( "gopher" )`]
|
||||
// [`"gopher:kyle:xy"`]
|
||||
// ][
|
||||
// [`"http://www.example.com//kyle:xy"`]
|
||||
// [`remove_authority()`]
|
||||
// [`"http:/.//kyle:xy"`]
|
||||
// ][
|
||||
// [`"//www.example.com//kyle:xy"`]
|
||||
// [`remove_authority()`]
|
||||
// [`"/.//kyle:xy"`]
|
||||
// ][
|
||||
// [`"http://www.example.com//kyle:xy"`]
|
||||
// [`remove_origin()`]
|
||||
// [`"/.//kyle:xy"`]
|
||||
// ][
|
||||
// [`"info:kyle:xy"`]
|
||||
// [`remove_origin()`]
|
||||
// [`"kyle%3Axy"`]
|
||||
// ][
|
||||
// [`"/kyle:xy"`]
|
||||
// [`set_path_absolute( false )`]
|
||||
// [`"kyle%3Axy"`]
|
||||
// ][
|
||||
// [`"kyle%3Axy"`]
|
||||
// [`set_path_absolute( true )`]
|
||||
// [`"/kyle:xy"`]
|
||||
// ][
|
||||
// [`""`]
|
||||
// [`set_path( "kyle:xy" )`]
|
||||
// [`"kyle%3Axy"`]
|
||||
// ][
|
||||
// [`""`]
|
||||
// [`set_path( "//foo/fighters.txt" )`]
|
||||
// [`"/.//foo/fighters.txt"`]
|
||||
// ][
|
||||
// [`"my%3Asharona/billa%3Abong"`]
|
||||
// [`normalize()`]
|
||||
// [`"my%3Asharona/billa:bong"`]
|
||||
// ][
|
||||
// [`"./my:sharona"`]
|
||||
// [`normalize()`]
|
||||
// [`"my%3Asharona"`]
|
||||
// ]]
|
||||
[cols="a,a,a"]
|
||||
|===
|
||||
// Headers
|
||||
|URL|Operation|Result
|
||||
|
||||
// Row 1, Column 1
|
||||
|`"info:kyle:xy"`
|
||||
// Row 1, Column 2
|
||||
|`remove_scheme()`
|
||||
// Row 1, Column 3
|
||||
|`"kyle%3Axy"`
|
||||
|
||||
// Row 2, Column 1
|
||||
|`"kyle%3Axy"`
|
||||
// Row 2, Column 2
|
||||
|`set_scheme( "gopher" )`
|
||||
// Row 2, Column 3
|
||||
|`"gopher:kyle:xy"`
|
||||
|
||||
// Row 3, Column 1
|
||||
|`"http://www.example.com//kyle:xy"`
|
||||
// Row 3, Column 2
|
||||
|`remove_authority()`
|
||||
// Row 3, Column 3
|
||||
|`"http:/.//kyle:xy"`
|
||||
|
||||
// Row 4, Column 1
|
||||
|`"//www.example.com//kyle:xy"`
|
||||
// Row 4, Column 2
|
||||
|`remove_authority()`
|
||||
// Row 4, Column 3
|
||||
|`"/.//kyle:xy"`
|
||||
|
||||
// Row 5, Column 1
|
||||
|`"http://www.example.com//kyle:xy"`
|
||||
// Row 5, Column 2
|
||||
|`remove_origin()`
|
||||
// Row 5, Column 3
|
||||
|`"/.//kyle:xy"`
|
||||
|
||||
// Row 6, Column 1
|
||||
|`"info:kyle:xy"`
|
||||
// Row 6, Column 2
|
||||
|`remove_origin()`
|
||||
// Row 6, Column 3
|
||||
|`"kyle%3Axy"`
|
||||
|
||||
// Row 7, Column 1
|
||||
|`"/kyle:xy"`
|
||||
// Row 7, Column 2
|
||||
|`set_path_absolute( false )`
|
||||
// Row 7, Column 3
|
||||
|`"kyle%3Axy"`
|
||||
|
||||
// Row 8, Column 1
|
||||
|`"kyle%3Axy"`
|
||||
// Row 8, Column 2
|
||||
|`set_path_absolute( true )`
|
||||
// Row 8, Column 3
|
||||
|`"/kyle:xy"`
|
||||
|
||||
// Row 9, Column 1
|
||||
|`""`
|
||||
// Row 9, Column 2
|
||||
|`set_path( "kyle:xy" )`
|
||||
// Row 9, Column 3
|
||||
|`"kyle%3Axy"`
|
||||
|
||||
// Row 10, Column 1
|
||||
|`""`
|
||||
// Row 10, Column 2
|
||||
|`set_path( "//foo/fighters.txt" )`
|
||||
// Row 10, Column 3
|
||||
|`"/.//foo/fighters.txt"`
|
||||
|
||||
// Row 11, Column 1
|
||||
|`"my%3Asharona/billa%3Abong"`
|
||||
// Row 11, Column 2
|
||||
|`normalize()`
|
||||
// Row 11, Column 3
|
||||
|`"my%3Asharona/billa:bong"`
|
||||
|
||||
// Row 12, Column 1
|
||||
|`"./my:sharona"`
|
||||
// Row 12, Column 2
|
||||
|`normalize()`
|
||||
// Row 12, Column 3
|
||||
|`"my%3Asharona"`
|
||||
|
||||
|===
|
||||
|
||||
|
||||
For the full set of containers and functions for operating
|
||||
on paths and segments, please consult the reference.
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
//
|
||||
|
||||
|
||||
== String Token
|
||||
= String Token
|
||||
|
||||
Functions which perform percent-decoding return values using
|
||||
`std::string` when called without special arguments. This is
|
||||
https://en.cppreference.com/w/cpp/string/basic_string[`std::string`,window=blank_] when called without special arguments. This is
|
||||
the best default for ergonomics, and a good enough default for
|
||||
performance considering that many decoded strings fit in
|
||||
the small buffer available to most standard implementations.
|
||||
@@ -23,7 +23,7 @@ algorithms acquire and store data in strings, for example:
|
||||
* Appending to existing strings
|
||||
|
||||
The library provides a special customization mechanism called
|
||||
`StringToken` to control how algorithms which require an output
|
||||
__StringToken__ to control how algorithms which require an output
|
||||
buffer acquire their storage. The signature
|
||||
|
||||
|
||||
|
||||
@@ -4,112 +4,20 @@
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Official repository: https://github.com/cppalliance/json
|
||||
Official repository: https://github.com/cppalliance/url
|
||||
]
|
||||
|
||||
[/-----------------------------------------------------------------------------]
|
||||
|
||||
[section Examples]
|
||||
|
||||
[section QR Code]
|
||||
|
||||
A QR code is a machine-readable two-dimensional barcode. They might contain data
|
||||
for a identifier or a URL to a website.
|
||||
|
||||
This example shows how to construct and modify URLs to consume a third party API to
|
||||
generate QR Codes.
|
||||
|
||||
[example_qrcode]
|
||||
[endsect]
|
||||
|
||||
[section Finicky]
|
||||
|
||||
This example shows how to classify URLs according to a set of rules. It is
|
||||
inspired by [@https://github.com/johnste/finicky Finicky] application.
|
||||
|
||||
The URLs are classified and redirected to a browser according to their
|
||||
category. See the example `config.json` file.
|
||||
|
||||
[example_finicky]
|
||||
[endsect]
|
||||
|
||||
[section mailto URLs]
|
||||
|
||||
`mailto` is a URL scheme for email addresses. `mailto` URL are used on websites
|
||||
to allow users to send an email to a specific address directly from an HTML document.
|
||||
|
||||
This example parses a mailto URL into a new view type and prints its components to
|
||||
standard output.
|
||||
|
||||
[example_mailto]
|
||||
[endsect]
|
||||
|
||||
[section Magnet Link]
|
||||
|
||||
`magnet` is a URL scheme for identifying files by their content. These files are
|
||||
usually identified by cryptographic hash value.
|
||||
|
||||
Magnet links are useful in peer-to-peer file sharing networks because they allow
|
||||
resources to be referred to without the need for a continuously available host..
|
||||
|
||||
This example parses a magnet link into a new view type and prints its components to
|
||||
standard output.
|
||||
|
||||
[example_magnet]
|
||||
[endsect]
|
||||
|
||||
[section File Router]
|
||||
|
||||
This example defines a router that associates URL paths to a directory in the filesystem. If
|
||||
the specified route matches and the file exists, the example prints its contents to standard output.
|
||||
|
||||
[example_file_router]
|
||||
[endsect]
|
||||
|
||||
[section Router]
|
||||
|
||||
This example defines a router for URL paths. If the specified route matches one of the existing
|
||||
routes, the example executes the underlying callback function.
|
||||
|
||||
[example_router]
|
||||
[endsect]
|
||||
|
||||
[section Sanitizing URLs]
|
||||
|
||||
This example parses a non-strict or invalid URL
|
||||
into path components according to its delimiters.
|
||||
This pattern can be adapted to the requirements of other
|
||||
applications.
|
||||
|
||||
Once the non-strict components are determined, a new URL is
|
||||
created and its parts are set with the `set_encoded_X`
|
||||
functions, which will encode any invalid chars accordingly.
|
||||
|
||||
This sort of transformation is useful in applications that are
|
||||
extremely loose in what kinds of URLs they accept, such as
|
||||
browsers. The sanitized URL can later be used for machine-to-machine
|
||||
communication.
|
||||
|
||||
Using non-strict URLs directly is a security concern in
|
||||
machine-to-machine communication, is ambiguous, and also
|
||||
involve an extra cost for the transformations.
|
||||
|
||||
Different transformations are required by different applications to
|
||||
construct a valid URL appropriate for machine-to-machine communication.
|
||||
For instance, if an invalid relative reference includes something that
|
||||
looks like a host in the first path segment, browsers usually interpret
|
||||
that as the host with an implicit "https" scheme. Other applications
|
||||
also have other implicit schemes.
|
||||
|
||||
The example also identifies whether the input url is already valid.
|
||||
It includes diagnostics that can be used to help the user determine
|
||||
if a URL is invalid and why it's invalid.
|
||||
|
||||
Once all transformations are applied, the result is a URL
|
||||
appropriate for machine-to-machine communication.
|
||||
|
||||
[example_sanitize_url]
|
||||
[endsect]
|
||||
[include 6.1.qrcode.qbk]
|
||||
[include 6.2.finicky.qbk]
|
||||
[include 6.3.mailto.qbk]
|
||||
[include 6.4.magnet-link.qbk]
|
||||
[include 6.5.file-router.qbk]
|
||||
[include 6.6.router.qbk]
|
||||
[include 6.7.sanitize.qbk]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
21
doc/qbk/6.1.qrcode.qbk
Normal file
21
doc/qbk/6.1.qrcode.qbk
Normal file
@@ -0,0 +1,21 @@
|
||||
[/
|
||||
Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Official repository: https://github.com/cppalliance/url
|
||||
]
|
||||
|
||||
[/-----------------------------------------------------------------------------]
|
||||
|
||||
[section QR Code]
|
||||
|
||||
A QR code is a machine-readable two-dimensional barcode. They might contain data
|
||||
for a identifier or a URL to a website.
|
||||
|
||||
This example shows how to construct and modify URLs to consume a third party API to
|
||||
generate QR Codes.
|
||||
|
||||
[example_qrcode]
|
||||
[endsect]
|
||||
21
doc/qbk/6.2.finicky.qbk
Normal file
21
doc/qbk/6.2.finicky.qbk
Normal file
@@ -0,0 +1,21 @@
|
||||
[/
|
||||
Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Official repository: https://github.com/cppalliance/url
|
||||
]
|
||||
|
||||
[/-----------------------------------------------------------------------------]
|
||||
|
||||
[section Finicky]
|
||||
|
||||
This example shows how to classify URLs according to a set of rules. It is
|
||||
inspired by [@https://github.com/johnste/finicky Finicky] application.
|
||||
|
||||
The URLs are classified and redirected to a browser according to their
|
||||
category. See the example `config.json` file.
|
||||
|
||||
[example_finicky]
|
||||
[endsect]
|
||||
21
doc/qbk/6.3.mailto.qbk
Normal file
21
doc/qbk/6.3.mailto.qbk
Normal file
@@ -0,0 +1,21 @@
|
||||
[/
|
||||
Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Official repository: https://github.com/cppalliance/url
|
||||
]
|
||||
|
||||
[/-----------------------------------------------------------------------------]
|
||||
|
||||
[section mailto URLs]
|
||||
|
||||
`mailto` is a URL scheme for email addresses. `mailto` URL are used on websites
|
||||
to allow users to send an email to a specific address directly from an HTML document.
|
||||
|
||||
This example parses a mailto URL into a new view type and prints its components to
|
||||
standard output.
|
||||
|
||||
[example_mailto]
|
||||
[endsect]
|
||||
24
doc/qbk/6.4.magnet-link.qbk
Normal file
24
doc/qbk/6.4.magnet-link.qbk
Normal file
@@ -0,0 +1,24 @@
|
||||
[/
|
||||
Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Official repository: https://github.com/cppalliance/url
|
||||
]
|
||||
|
||||
[/-----------------------------------------------------------------------------]
|
||||
|
||||
[section Magnet Link]
|
||||
|
||||
`magnet` is a URL scheme for identifying files by their content. These files are
|
||||
usually identified by cryptographic hash value.
|
||||
|
||||
Magnet links are useful in peer-to-peer file sharing networks because they allow
|
||||
resources to be referred to without the need for a continuously available host..
|
||||
|
||||
This example parses a magnet link into a new view type and prints its components to
|
||||
standard output.
|
||||
|
||||
[example_magnet]
|
||||
[endsect]
|
||||
19
doc/qbk/6.5.file-router.qbk
Normal file
19
doc/qbk/6.5.file-router.qbk
Normal file
@@ -0,0 +1,19 @@
|
||||
[/
|
||||
Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Official repository: https://github.com/cppalliance/url
|
||||
]
|
||||
|
||||
[/-----------------------------------------------------------------------------]
|
||||
|
||||
[section File Router]
|
||||
|
||||
This example defines a router that associates URL paths to a directory in the filesystem. If
|
||||
the specified route matches and the file exists, the example prints its contents to standard output.
|
||||
|
||||
[example_file_router]
|
||||
[endsect]
|
||||
|
||||
19
doc/qbk/6.6.router.qbk
Normal file
19
doc/qbk/6.6.router.qbk
Normal file
@@ -0,0 +1,19 @@
|
||||
[/
|
||||
Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Official repository: https://github.com/cppalliance/url
|
||||
]
|
||||
|
||||
[/-----------------------------------------------------------------------------]
|
||||
|
||||
[section Router]
|
||||
|
||||
This example defines a router for URL paths. If the specified route matches one of the existing
|
||||
routes, the example executes the underlying callback function.
|
||||
|
||||
[example_router]
|
||||
[endsect]
|
||||
|
||||
47
doc/qbk/6.7.sanitize.qbk
Normal file
47
doc/qbk/6.7.sanitize.qbk
Normal file
@@ -0,0 +1,47 @@
|
||||
[/
|
||||
Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Official repository: https://github.com/cppalliance/url
|
||||
]
|
||||
|
||||
[/-----------------------------------------------------------------------------]
|
||||
|
||||
[section Sanitizing URLs]
|
||||
|
||||
This example parses a non-strict or invalid URL
|
||||
into path components according to its delimiters.
|
||||
This pattern can be adapted to the requirements of other
|
||||
applications.
|
||||
|
||||
Once the non-strict components are determined, a new URL is
|
||||
created and its parts are set with the `set_encoded_X`
|
||||
functions, which will encode any invalid chars accordingly.
|
||||
|
||||
This sort of transformation is useful in applications that are
|
||||
extremely loose in what kinds of URLs they accept, such as
|
||||
browsers. The sanitized URL can later be used for machine-to-machine
|
||||
communication.
|
||||
|
||||
Using non-strict URLs directly is a security concern in
|
||||
machine-to-machine communication, is ambiguous, and also
|
||||
involve an extra cost for the transformations.
|
||||
|
||||
Different transformations are required by different applications to
|
||||
construct a valid URL appropriate for machine-to-machine communication.
|
||||
For instance, if an invalid relative reference includes something that
|
||||
looks like a host in the first path segment, browsers usually interpret
|
||||
that as the host with an implicit "https" scheme. Other applications
|
||||
also have other implicit schemes.
|
||||
|
||||
The example also identifies whether the input url is already valid.
|
||||
It includes diagnostics that can be used to help the user determine
|
||||
if a URL is invalid and why it's invalid.
|
||||
|
||||
Once all transformations are applied, the result is a URL
|
||||
appropriate for machine-to-machine communication.
|
||||
|
||||
[example_sanitize_url]
|
||||
[endsect]
|
||||
Reference in New Issue
Block a user