url.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * Copyright 2011-2020 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* term = _url.getTerm();
  23. StringView schemeEnd = strFind(_url, "://");
  24. const char* hostStart = !schemeEnd.isEmpty() ? schemeEnd.getTerm() : _url.getPtr();
  25. StringView path = strFind(StringView(hostStart, term), '/');
  26. if (schemeEnd.isEmpty()
  27. && path.isEmpty() )
  28. {
  29. return false;
  30. }
  31. if (!schemeEnd.isEmpty()
  32. && (path.isEmpty() || path.getPtr() > schemeEnd.getPtr() ) )
  33. {
  34. const StringView scheme(_url.getPtr(), schemeEnd.getPtr() );
  35. if (!isAlpha(scheme) )
  36. {
  37. return false;
  38. }
  39. m_tokens[Scheme].set(scheme);
  40. }
  41. if (!path.isEmpty() )
  42. {
  43. path.set(path.getPtr(), term);
  44. const StringView query = strFind(path, '?');
  45. const StringView fragment = strFind(path, '#');
  46. if (!fragment.isEmpty()
  47. && fragment.getPtr() < query.getPtr() )
  48. {
  49. return false;
  50. }
  51. m_tokens[Path].set(path.getPtr()
  52. , !query.isEmpty() ? query.getPtr()
  53. : !fragment.isEmpty() ? fragment.getPtr()
  54. : term
  55. );
  56. if (!query.isEmpty() )
  57. {
  58. m_tokens[Query].set(query.getPtr()+1
  59. , !fragment.isEmpty() ? fragment.getPtr()
  60. : term
  61. );
  62. }
  63. if (!fragment.isEmpty() )
  64. {
  65. m_tokens[Fragment].set(fragment.getPtr()+1, term);
  66. }
  67. term = path.getPtr();
  68. }
  69. const StringView userPassEnd = strFind(StringView(hostStart, term), '@');
  70. const char* userPassStart = !userPassEnd.isEmpty() ? hostStart : NULL;
  71. hostStart = !userPassEnd.isEmpty() ? userPassEnd.getPtr()+1 : hostStart;
  72. const StringView portStart = strFind(StringView(hostStart, term), ':');
  73. m_tokens[Host].set(hostStart, !portStart.isEmpty() ? portStart.getPtr() : term);
  74. if (!portStart.isEmpty())
  75. {
  76. m_tokens[Port].set(portStart.getPtr()+1, term);
  77. }
  78. if (NULL != userPassStart)
  79. {
  80. StringView passStart = strFind(StringView(userPassStart, userPassEnd.getPtr() ), ':');
  81. m_tokens[UserName].set(userPassStart
  82. , !passStart.isEmpty() ? passStart.getPtr()
  83. : userPassEnd.getPtr()
  84. );
  85. if (!passStart.isEmpty() )
  86. {
  87. m_tokens[Password].set(passStart.getPtr()+1, userPassEnd.getPtr() );
  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