internal.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. This file is part of libmicrohttpd
  3. Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with this library; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  15. */
  16. /**
  17. * @file microhttpd/internal.c
  18. * @brief internal shared structures
  19. * @author Daniel Pittman
  20. * @author Christian Grothoff
  21. */
  22. #include "internal.h"
  23. #include "mhd_str.h"
  24. #ifdef HAVE_MESSAGES
  25. #if DEBUG_STATES
  26. /**
  27. * State to string dictionary.
  28. */
  29. const char *
  30. MHD_state_to_string (enum MHD_CONNECTION_STATE state)
  31. {
  32. switch (state)
  33. {
  34. case MHD_CONNECTION_INIT:
  35. return "connection init";
  36. case MHD_CONNECTION_URL_RECEIVED:
  37. return "connection url received";
  38. case MHD_CONNECTION_HEADER_PART_RECEIVED:
  39. return "header partially received";
  40. case MHD_CONNECTION_HEADERS_RECEIVED:
  41. return "headers received";
  42. case MHD_CONNECTION_HEADERS_PROCESSED:
  43. return "headers processed";
  44. case MHD_CONNECTION_CONTINUE_SENDING:
  45. return "continue sending";
  46. case MHD_CONNECTION_CONTINUE_SENT:
  47. return "continue sent";
  48. case MHD_CONNECTION_BODY_RECEIVED:
  49. return "body received";
  50. case MHD_CONNECTION_FOOTER_PART_RECEIVED:
  51. return "footer partially received";
  52. case MHD_CONNECTION_FOOTERS_RECEIVED:
  53. return "footers received";
  54. case MHD_CONNECTION_HEADERS_SENDING:
  55. return "headers sending";
  56. case MHD_CONNECTION_HEADERS_SENT:
  57. return "headers sent";
  58. case MHD_CONNECTION_NORMAL_BODY_READY:
  59. return "normal body ready";
  60. case MHD_CONNECTION_NORMAL_BODY_UNREADY:
  61. return "normal body unready";
  62. case MHD_CONNECTION_CHUNKED_BODY_READY:
  63. return "chunked body ready";
  64. case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
  65. return "chunked body unready";
  66. case MHD_CONNECTION_BODY_SENT:
  67. return "body sent";
  68. case MHD_CONNECTION_FOOTERS_SENDING:
  69. return "footers sending";
  70. case MHD_CONNECTION_FOOTERS_SENT:
  71. return "footers sent";
  72. case MHD_CONNECTION_CLOSED:
  73. return "closed";
  74. default:
  75. return "unrecognized connection state";
  76. }
  77. }
  78. #endif
  79. #endif
  80. #ifdef HAVE_MESSAGES
  81. /**
  82. * fprintf-like helper function for logging debug
  83. * messages.
  84. */
  85. void
  86. MHD_DLOG (const struct MHD_Daemon *daemon,
  87. enum MHD_StatusCode sc,
  88. const char *format,
  89. ...)
  90. {
  91. va_list va;
  92. if (NULL == daemon->logger)
  93. return;
  94. va_start (va,
  95. format);
  96. daemon->logger (daemon->logger_cls,
  97. sc,
  98. format,
  99. va);
  100. va_end (va);
  101. }
  102. #endif
  103. /**
  104. * Convert all occurrences of '+' to ' '.
  105. *
  106. * @param arg string that is modified (in place), must be 0-terminated
  107. */
  108. void
  109. MHD_unescape_plus (char *arg)
  110. {
  111. char *p;
  112. for (p = strchr (arg, '+'); NULL != p; p = strchr (p + 1, '+'))
  113. *p = ' ';
  114. }
  115. /**
  116. * Process escape sequences ('%HH') Updates val in place; the
  117. * result should be UTF-8 encoded and cannot be larger than the input.
  118. * The result must also still be 0-terminated.
  119. *
  120. * @param val value to unescape (modified in the process)
  121. * @return length of the resulting val (strlen(val) maybe
  122. * shorter afterwards due to elimination of escape sequences)
  123. */
  124. size_t
  125. MHD_http_unescape (char *val)
  126. {
  127. char *rpos = val;
  128. char *wpos = val;
  129. while ('\0' != *rpos)
  130. {
  131. uint32_t num;
  132. switch (*rpos)
  133. {
  134. case '%':
  135. if (2 == MHD_strx_to_uint32_n_ (rpos + 1,
  136. 2,
  137. &num))
  138. {
  139. *wpos = (char) ((unsigned char) num);
  140. wpos++;
  141. rpos += 3;
  142. break;
  143. }
  144. /* TODO: add bad sequence handling */
  145. /* intentional fall through! */
  146. default:
  147. *wpos = *rpos;
  148. wpos++;
  149. rpos++;
  150. }
  151. }
  152. *wpos = '\0'; /* add 0-terminator */
  153. return wpos - val; /* = strlen(val) */
  154. }
  155. /**
  156. * Parse and unescape the arguments given by the client
  157. * as part of the HTTP request URI.
  158. *
  159. * @param request request to add headers to
  160. * @param kind header kind to pass to @a cb
  161. * @param[in,out] args argument URI string (after "?" in URI),
  162. * clobbered in the process!
  163. * @param cb function to call on each key-value pair found
  164. * @param[out] num_headers set to the number of headers found
  165. * @return false on failure (@a cb returned false),
  166. * true for success (parsing succeeded, @a cb always
  167. * returned true)
  168. */
  169. bool
  170. MHD_parse_arguments_ (struct MHD_Request *request,
  171. enum MHD_ValueKind kind,
  172. char *args,
  173. MHD_ArgumentIterator_ cb,
  174. unsigned int *num_headers)
  175. {
  176. struct MHD_Daemon *daemon = request->daemon;
  177. char *equals;
  178. char *amper;
  179. *num_headers = 0;
  180. while ( (NULL != args) &&
  181. ('\0' != args[0]) )
  182. {
  183. equals = strchr (args, '=');
  184. amper = strchr (args, '&');
  185. if (NULL == amper)
  186. {
  187. /* last argument */
  188. if (NULL == equals)
  189. {
  190. /* last argument, without '=' */
  191. MHD_unescape_plus (args);
  192. daemon->unescape_cb (daemon->unescape_cb_cls,
  193. request,
  194. args);
  195. if (! cb (request,
  196. args,
  197. NULL,
  198. kind))
  199. return false;
  200. (*num_headers)++;
  201. break;
  202. }
  203. /* got 'foo=bar' */
  204. equals[0] = '\0';
  205. equals++;
  206. MHD_unescape_plus (args);
  207. daemon->unescape_cb (daemon->unescape_cb_cls,
  208. request,
  209. args);
  210. MHD_unescape_plus (equals);
  211. daemon->unescape_cb (daemon->unescape_cb_cls,
  212. request,
  213. equals);
  214. if (! cb (request,
  215. args,
  216. equals,
  217. kind))
  218. return false;
  219. (*num_headers)++;
  220. break;
  221. }
  222. /* amper is non-NULL here */
  223. amper[0] = '\0';
  224. amper++;
  225. if ( (NULL == equals) ||
  226. (equals >= amper) )
  227. {
  228. /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */
  229. MHD_unescape_plus (args);
  230. daemon->unescape_cb (daemon->unescape_cb_cls,
  231. request,
  232. args);
  233. if (! cb (request,
  234. args,
  235. NULL,
  236. kind))
  237. return false;
  238. /* continue with 'bar' */
  239. (*num_headers)++;
  240. args = amper;
  241. continue;
  242. }
  243. /* equals and amper are non-NULL here, and equals < amper,
  244. so we got regular 'foo=value&bar...'-kind of argument */
  245. equals[0] = '\0';
  246. equals++;
  247. MHD_unescape_plus (args);
  248. daemon->unescape_cb (daemon->unescape_cb_cls,
  249. request,
  250. args);
  251. MHD_unescape_plus (equals);
  252. daemon->unescape_cb (daemon->unescape_cb_cls,
  253. request,
  254. equals);
  255. if (! cb (request,
  256. args,
  257. equals,
  258. kind))
  259. return false;
  260. (*num_headers)++;
  261. args = amper;
  262. }
  263. return true;
  264. }
  265. /* end of internal.c */