io_emb.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*
  2. * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
  3. * All rights reserved
  4. *
  5. * "THE BEER-WARE LICENSE" (Revision 42):
  6. * Sergey Lyubka wrote this file. As long as you retain this notice you
  7. * can do whatever you want with this stuff. If we meet some day, and you think
  8. * this stuff is worth it, you can buy me a beer in return.
  9. */
  10. #include "defs.h"
  11. const char *
  12. shttpd_version(void)
  13. {
  14. return (VERSION);
  15. }
  16. static void
  17. call_user(struct conn *c, struct shttpd_arg *arg, shttpd_callback_t func)
  18. {
  19. arg->priv = c;
  20. arg->state = c->loc.chan.emb.state;
  21. arg->out.buf = io_space(&c->loc.io);
  22. arg->out.len = io_space_len(&c->loc.io);
  23. arg->out.num_bytes = 0;
  24. arg->in.buf = io_data(&c->rem.io);;
  25. arg->in.len = io_data_len(&c->rem.io);
  26. arg->in.num_bytes = 0;
  27. if (io_data_len(&c->rem.io) >= c->rem.io.size)
  28. arg->flags |= SHTTPD_POST_BUFFER_FULL;
  29. if (c->rem.content_len > 0 && c->rem.io.total < c->rem.content_len)
  30. arg->flags |= SHTTPD_MORE_POST_DATA;
  31. func(arg);
  32. io_inc_head(&c->loc.io, arg->out.num_bytes);
  33. io_inc_tail(&c->rem.io, arg->in.num_bytes);
  34. c->loc.chan.emb.state = arg->state; /* Save state */
  35. /*
  36. * If callback finished output, that means it did all cleanup.
  37. * If the connection is terminated unexpectedly, we canna call
  38. * the callback via the stream close() method from disconnect.
  39. * However, if cleanup is already done, we set close() method to
  40. * NULL, to prevent the call from disconnect().
  41. */
  42. if (arg->flags & SHTTPD_END_OF_OUTPUT)
  43. c->loc.flags &= ~FLAG_DONT_CLOSE;
  44. else
  45. c->loc.flags |= FLAG_DONT_CLOSE;
  46. if (arg->flags & SHTTPD_SUSPEND)
  47. c->loc.flags |= FLAG_SUSPEND;
  48. }
  49. static int
  50. do_embedded(struct stream *stream, void *buf, size_t len)
  51. {
  52. struct shttpd_arg arg;
  53. buf = NULL; len = 0; /* Squash warnings */
  54. arg.user_data = stream->conn->loc.chan.emb.data;
  55. arg.flags = 0;
  56. call_user(stream->conn, &arg, (shttpd_callback_t)
  57. stream->conn->loc.chan.emb.func.v_func);
  58. return (0);
  59. }
  60. static void
  61. close_embedded(struct stream *stream)
  62. {
  63. struct shttpd_arg arg;
  64. struct conn *c = stream->conn;
  65. arg.flags = SHTTPD_CONNECTION_ERROR;
  66. arg.user_data = c->loc.chan.emb.data;
  67. /*
  68. * Do not call the user function if SHTTPD_END_OF_OUTPUT was set,
  69. * i.e. the callback already terminated correctly
  70. */
  71. if (stream->flags & FLAG_DONT_CLOSE)
  72. call_user(stream->conn, &arg, (shttpd_callback_t)
  73. c->loc.chan.emb.func.v_func);
  74. }
  75. size_t
  76. shttpd_printf(struct shttpd_arg *arg, const char *fmt, ...)
  77. {
  78. char *buf = arg->out.buf + arg->out.num_bytes;
  79. int buflen = arg->out.len - arg->out.num_bytes, len = 0;
  80. va_list ap;
  81. if (buflen > 0) {
  82. va_start(ap, fmt);
  83. len = vsnprintf(buf, buflen, fmt, ap);
  84. va_end(ap);
  85. if (len < 0 || len > buflen)
  86. len = buflen;
  87. arg->out.num_bytes += len;
  88. }
  89. return (len);
  90. }
  91. const char *
  92. shttpd_get_header(struct shttpd_arg *arg, const char *header_name)
  93. {
  94. struct conn *c = arg->priv;
  95. char *p, *s, *e;
  96. size_t len;
  97. p = c->headers;
  98. e = c->request + c->rem.headers_len;
  99. len = strlen(header_name);
  100. while (p < e) {
  101. if ((s = strchr(p, '\n')) != NULL)
  102. s[s[-1] == '\r' ? -1 : 0] = '\0';
  103. if (_shttpd_strncasecmp(header_name, p, len) == 0)
  104. return (p + len + 2);
  105. p += strlen(p) + 1;
  106. }
  107. return (NULL);
  108. }
  109. const char *
  110. shttpd_get_boundary(struct shttpd_arg *arg, int *boundary_length) {
  111. const char* content_type = shttpd_get_header(arg, "Content-Type");
  112. if (content_type == NULL) {
  113. return NULL;
  114. }
  115. const char* flag = "boundary=";
  116. const char* begin = strstr(content_type, flag);
  117. if (begin == NULL) {
  118. *boundary_length = 0;
  119. return NULL;
  120. }
  121. begin += strlen(flag);
  122. int len = 0;
  123. while (!(begin[len] == '\r' || begin[len] == '\0' || begin[len] == ';')) {
  124. ++len;
  125. }
  126. *boundary_length = len;
  127. return begin;
  128. }
  129. const char *
  130. shttpd_get_env(struct shttpd_arg *arg, const char *env_name)
  131. {
  132. struct conn *c = arg->priv;
  133. struct vec *vec;
  134. if (strcmp(env_name, "REQUEST_METHOD") == 0) {
  135. return (_shttpd_known_http_methods[c->method].ptr);
  136. } else if (strcmp(env_name, "REQUEST_URI") == 0) {
  137. return (c->uri);
  138. } else if (strcmp(env_name, "QUERY_STRING") == 0) {
  139. return (c->query);
  140. } else if (strcmp(env_name, "REMOTE_USER") == 0) {
  141. vec = &c->ch.user.v_vec;
  142. if (vec->len > 0) {
  143. ((char *) vec->ptr)[vec->len] = '\0';
  144. return (vec->ptr);
  145. }
  146. } else if (strcmp(env_name, "REMOTE_ADDR") == 0) {
  147. return (inet_ntoa(c->sa.u.sin.sin_addr));/* FIXME NOT MT safe */
  148. }
  149. return (NULL);
  150. }
  151. void
  152. shttpd_get_http_version(struct shttpd_arg *arg,
  153. unsigned long *major, unsigned long *minor)
  154. {
  155. struct conn *c = arg->priv;
  156. *major = c->major_version;
  157. *minor = c->minor_version;
  158. }
  159. void
  160. shttpd_register_uri(struct shttpd_ctx *ctx,
  161. const char *uri, shttpd_callback_t callback, void *data)
  162. {
  163. struct registered_uri *e;
  164. if ((e = malloc(sizeof(*e))) != NULL) {
  165. e->uri = _shttpd_strdup(uri);
  166. e->callback.v_func = (void (*)(void)) callback;
  167. e->callback_data = data;
  168. LL_TAIL(&ctx->registered_uris, &e->link);
  169. }
  170. }
  171. int
  172. shttpd_get_var(const char *var, const char *buf, int buf_len,
  173. char *value, int value_len)
  174. {
  175. const char *p, *e, *s;
  176. size_t var_len;
  177. var_len = strlen(var);
  178. e = buf + buf_len; /* End of QUERY_STRING buffer */
  179. /* buf is "var1=val1&var2=val2...". Find variable first */
  180. for (p = buf; p + var_len < e; p++)
  181. if ((p == buf || p[-1] == '&') &&
  182. p[var_len] == '=' &&
  183. !_shttpd_strncasecmp(var, p, var_len)) {
  184. /* Point 'p' to var value, 's' to the end of value */
  185. p += var_len + 1;
  186. if ((s = memchr(p, '&', e - p)) == NULL)
  187. s = e;
  188. /* URL-decode value. Return result length */
  189. return (_shttpd_url_decode(p, s - p, value, value_len));
  190. }
  191. return (-1);
  192. }
  193. static int
  194. match_regexp(const char *regexp, const char *text)
  195. {
  196. if (*regexp == '\0')
  197. return (*text == '\0');
  198. if (*regexp == '*')
  199. do {
  200. if (match_regexp(regexp + 1, text))
  201. return (1);
  202. } while (*text++ != '\0');
  203. if (*text != '\0' && *regexp == *text)
  204. return (match_regexp(regexp + 1, text + 1));
  205. return (0);
  206. }
  207. struct registered_uri *
  208. _shttpd_is_registered_uri(struct shttpd_ctx *ctx, const char *uri)
  209. {
  210. struct llhead *lp;
  211. struct registered_uri *reg_uri;
  212. LL_FOREACH(&ctx->registered_uris, lp) {
  213. reg_uri = LL_ENTRY(lp, struct registered_uri, link);
  214. if (match_regexp(reg_uri->uri, uri))
  215. return (reg_uri);
  216. }
  217. return (NULL);
  218. }
  219. void
  220. _shttpd_setup_embedded_stream(struct conn *c, union variant func, void *data)
  221. {
  222. c->loc.chan.emb.state = NULL;
  223. c->loc.chan.emb.func = func;
  224. c->loc.chan.emb.data = data;
  225. c->loc.io_class = &_shttpd_io_embedded;
  226. c->loc.flags |= FLAG_R | FLAG_W |FLAG_ALWAYS_READY;
  227. }
  228. void
  229. shttpd_handle_error(struct shttpd_ctx *ctx, int code,
  230. shttpd_callback_t func, void *data)
  231. {
  232. struct error_handler *e;
  233. if ((e = malloc(sizeof(*e))) != NULL) {
  234. e->code = code;
  235. e->callback.v_func = (void (*)(void)) func;
  236. e->callback_data = data;
  237. LL_TAIL(&ctx->error_handlers, &e->link);
  238. }
  239. }
  240. void
  241. shttpd_wakeup(const void *priv)
  242. {
  243. const struct conn *conn = priv;
  244. char buf[sizeof(int) + sizeof(void *)];
  245. int cmd = CTL_WAKEUP;
  246. #if 0
  247. conn->flags &= ~SHTTPD_SUSPEND;
  248. #endif
  249. (void) memcpy(buf, &cmd, sizeof(cmd));
  250. (void) memcpy(buf + sizeof(cmd), conn, sizeof(conn));
  251. (void) send(conn->worker->ctl[1], buf, sizeof(buf), 0);
  252. }
  253. const struct io_class _shttpd_io_embedded = {
  254. "embedded",
  255. do_embedded,
  256. (int (*)(struct stream *, const void *, size_t)) do_embedded,
  257. close_embedded
  258. };