url.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bnet#license-bsd-2-clause
  4. */
  5. #include "bx_p.h"
  6. #include <bx/url.h>
  7. namespace bx
  8. {
  9. UrlView::UrlView()
  10. {
  11. }
  12. void UrlView::clear()
  13. {
  14. for (uint32_t ii = 0; ii < Count; ++ii)
  15. {
  16. m_tokens[ii].clear();
  17. }
  18. }
  19. bool UrlView::parse(const StringView& _url)
  20. {
  21. clear();
  22. const char* start = _url.getPtr();
  23. const char* term = _url.getTerm();
  24. const char* schemeEnd = strFind(StringView(start, term), "://");
  25. const char* hostStart = NULL != schemeEnd ? schemeEnd+3 : start;
  26. const char* pathStart = strFind(StringView(hostStart, term), '/');
  27. if (NULL == schemeEnd
  28. && NULL == pathStart)
  29. {
  30. return false;
  31. }
  32. if (NULL != schemeEnd
  33. && (NULL == pathStart || pathStart > schemeEnd) )
  34. {
  35. StringView scheme(start, schemeEnd);
  36. if (!isAlpha(scheme) )
  37. {
  38. return false;
  39. }
  40. m_tokens[Scheme].set(scheme);
  41. }
  42. if (NULL != pathStart)
  43. {
  44. const char* queryStart = strFind(StringView(pathStart, term), '?');
  45. const char* fragmentStart = strFind(StringView(pathStart, term), '#');
  46. if (NULL != fragmentStart
  47. && fragmentStart < queryStart)
  48. {
  49. return false;
  50. }
  51. m_tokens[Path].set(pathStart
  52. , NULL != queryStart ? queryStart
  53. : NULL != fragmentStart ? fragmentStart
  54. : term
  55. );
  56. if (NULL != queryStart)
  57. {
  58. m_tokens[Query].set(queryStart+1
  59. , NULL != fragmentStart ? fragmentStart
  60. : term
  61. );
  62. }
  63. if (NULL != fragmentStart)
  64. {
  65. m_tokens[Fragment].set(fragmentStart+1, term);
  66. }
  67. term = pathStart;
  68. }
  69. const char* userPassEnd = strFind(StringView(hostStart, term), '@');
  70. const char* userPassStart = NULL != userPassEnd ? hostStart : NULL;
  71. hostStart = NULL != userPassEnd ? userPassEnd+1 : hostStart;
  72. const char* portStart = strFind(StringView(hostStart, term), ':');
  73. m_tokens[Host].set(hostStart, NULL != portStart ? portStart : term);
  74. if (NULL != portStart)
  75. {
  76. m_tokens[Port].set(portStart+1, term);
  77. }
  78. if (NULL != userPassStart)
  79. {
  80. const char* passStart = strFind(StringView(userPassStart, userPassEnd), ':');
  81. m_tokens[UserName].set(userPassStart
  82. , NULL != passStart ? passStart
  83. : userPassEnd
  84. );
  85. if (NULL != passStart)
  86. {
  87. m_tokens[Password].set(passStart+1, userPassEnd);
  88. }
  89. }
  90. return true;
  91. }
  92. const StringView& UrlView::get(Enum _token) const
  93. {
  94. return m_tokens[_token];
  95. }
  96. static char toHex(char _nible)
  97. {
  98. return "0123456789ABCDEF"[_nible&0xf];
  99. }
  100. // https://secure.wikimedia.org/wikipedia/en/wiki/URL_encoding
  101. void urlEncode(char* _out, uint32_t _max, const StringView& _str)
  102. {
  103. _max--; // need space for zero terminator
  104. const char* str = _str.getPtr();
  105. const char* term = _str.getTerm();
  106. uint32_t ii = 0;
  107. for (char ch = *str++
  108. ; str <= term && ii < _max
  109. ; ch = *str++
  110. )
  111. {
  112. if (isAlphaNum(ch)
  113. || ch == '-'
  114. || ch == '_'
  115. || ch == '.'
  116. || ch == '~')
  117. {
  118. _out[ii++] = ch;
  119. }
  120. else if (ii+3 < _max)
  121. {
  122. _out[ii++] = '%';
  123. _out[ii++] = toHex(ch>>4);
  124. _out[ii++] = toHex(ch);
  125. }
  126. }
  127. _out[ii] = '\0';
  128. }
  129. } // namespace bx