url.cpp 3.1 KB

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