amqp_url.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /*
  2. * ***** BEGIN LICENSE BLOCK *****
  3. * Version: MIT
  4. *
  5. * Portions created by Alan Antonuk are Copyright (c) 2012-2013
  6. * Alan Antonuk. All Rights Reserved.
  7. *
  8. * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
  9. * All Rights Reserved.
  10. *
  11. * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
  12. * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
  13. *
  14. * Permission is hereby granted, free of charge, to any person
  15. * obtaining a copy of this software and associated documentation
  16. * files (the "Software"), to deal in the Software without
  17. * restriction, including without limitation the rights to use, copy,
  18. * modify, merge, publish, distribute, sublicense, and/or sell copies
  19. * of the Software, and to permit persons to whom the Software is
  20. * furnished to do so, subject to the following conditions:
  21. *
  22. * The above copyright notice and this permission notice shall be
  23. * included in all copies or substantial portions of the Software.
  24. *
  25. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  26. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  27. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  28. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  29. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  30. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  31. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  32. * SOFTWARE.
  33. * ***** END LICENSE BLOCK *****
  34. */
  35. #ifdef HAVE_CONFIG_H
  36. #include "config.h"
  37. #endif
  38. #ifdef _MSC_VER
  39. #define _CRT_SECURE_NO_WARNINGS
  40. #endif
  41. #include "amqp_private.h"
  42. #include <limits.h>
  43. #include <stdint.h>
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. void amqp_default_connection_info(struct amqp_connection_info *ci) {
  48. /* Apply defaults */
  49. ci->user = "guest";
  50. ci->password = "guest";
  51. ci->host = "localhost";
  52. ci->port = 5672;
  53. ci->vhost = "/";
  54. ci->ssl = 0;
  55. }
  56. /* Scan for the next delimiter, handling percent-encodings on the way. */
  57. static char find_delim(char **pp, int colon_and_at_sign_are_delims) {
  58. char *from = *pp;
  59. char *to = from;
  60. for (;;) {
  61. char ch = *from++;
  62. switch (ch) {
  63. case ':':
  64. case '@':
  65. if (!colon_and_at_sign_are_delims) {
  66. *to++ = ch;
  67. break;
  68. }
  69. /* fall through */
  70. case 0:
  71. case '/':
  72. case '?':
  73. case '#':
  74. case '[':
  75. case ']':
  76. *to = 0;
  77. *pp = from;
  78. return ch;
  79. case '%': {
  80. unsigned int val;
  81. int chars;
  82. int res = sscanf(from, "%2x%n", &val, &chars);
  83. if (res == EOF || res < 1 || chars != 2 || val > CHAR_MAX)
  84. /* Return a surprising delimiter to
  85. force an error. */
  86. {
  87. return '%';
  88. }
  89. *to++ = (char)val;
  90. from += 2;
  91. break;
  92. }
  93. default:
  94. *to++ = ch;
  95. break;
  96. }
  97. }
  98. }
  99. /* Parse an AMQP URL into its component parts. */
  100. int amqp_parse_url(char *url, struct amqp_connection_info *parsed) {
  101. int res = AMQP_STATUS_BAD_URL;
  102. char delim;
  103. char *start;
  104. char *host;
  105. char *port = NULL;
  106. amqp_default_connection_info(parsed);
  107. /* check the prefix */
  108. if (!strncmp(url, "amqp://", 7)) {
  109. /* do nothing */
  110. } else if (!strncmp(url, "amqps://", 8)) {
  111. parsed->port = 5671;
  112. parsed->ssl = 1;
  113. } else {
  114. goto out;
  115. }
  116. host = start = url += (parsed->ssl ? 8 : 7);
  117. delim = find_delim(&url, 1);
  118. if (delim == ':') {
  119. /* The colon could be introducing the port or the
  120. password part of the userinfo. We don't know yet,
  121. so stash the preceding component. */
  122. port = start = url;
  123. delim = find_delim(&url, 1);
  124. }
  125. if (delim == '@') {
  126. /* What might have been the host and port were in fact
  127. the username and password */
  128. parsed->user = host;
  129. if (port) {
  130. parsed->password = port;
  131. }
  132. port = NULL;
  133. host = start = url;
  134. delim = find_delim(&url, 1);
  135. }
  136. if (delim == '[') {
  137. /* IPv6 address. The bracket should be the first
  138. character in the host. */
  139. if (host != start || *host != 0) {
  140. goto out;
  141. }
  142. start = url;
  143. delim = find_delim(&url, 0);
  144. if (delim != ']') {
  145. goto out;
  146. }
  147. parsed->host = start;
  148. start = url;
  149. delim = find_delim(&url, 1);
  150. /* Closing bracket should be the last character in the
  151. host. */
  152. if (*start != 0) {
  153. goto out;
  154. }
  155. } else {
  156. /* If we haven't seen the host yet, this is it. */
  157. if (*host != 0) {
  158. parsed->host = host;
  159. }
  160. }
  161. if (delim == ':') {
  162. port = start = url;
  163. delim = find_delim(&url, 1);
  164. }
  165. if (port) {
  166. char *end;
  167. long portnum = strtol(port, &end, 10);
  168. if (port == end || *end != 0 || portnum < 0 || portnum > 65535) {
  169. goto out;
  170. }
  171. parsed->port = portnum;
  172. }
  173. if (delim == '/') {
  174. start = url;
  175. delim = find_delim(&url, 1);
  176. if (delim != 0) {
  177. goto out;
  178. }
  179. parsed->vhost = start;
  180. res = AMQP_STATUS_OK;
  181. } else if (delim == 0) {
  182. res = AMQP_STATUS_OK;
  183. }
  184. /* Any other delimiter is bad, and we will return AMQP_STATUS_BAD_AMQP_URL. */
  185. out:
  186. return res;
  187. }