ctorrent stat collector
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
6.3KB

  1. /***************************************************************************
  2. * Copyright (C) 07/2007 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; version 2 of the License *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <unistd.h>
  22. #include <string.h>
  23. #include <sys/time.h>
  24. #include <sys/types.h>
  25. #include <sys/ioctl.h>
  26. #include "event.h"
  27. #include "httpd.h"
  28. #include "list.h"
  29. #include "logging.h"
  30. #include "sockaddr.h"
  31. #include "tcpsocket.h"
  32. static LIST_HEAD(httpd_cb_list);
  33. static void destroy_httpd_con(struct httpd_con *con)
  34. {
  35. close(event_get_fd(con->event));
  36. event_remove_fd(con->event);
  37. if (con->req_data != NULL)
  38. free(con->req_data);
  39. if (con->req_headers != NULL)
  40. free(con->req_headers);
  41. if (con->req_args != NULL)
  42. free(con->req_args);
  43. free(con);
  44. }
  45. int httpd_send_header(struct httpd_con *con, char *code, char *type)
  46. {
  47. char buf[256];
  48. int len = snprintf(buf, sizeof(buf), "HTTP/1.0 %s\r\nContent-Type: %s\r\nConnection: close\r\n\r\n", code, type);
  49. write(con->fd, buf, len);
  50. return 0;
  51. }
  52. int httpd_send_error(struct httpd_con *con, char *code, char *msg)
  53. {
  54. httpd_send_header(con, code, "text/plain");
  55. write(con->fd, msg, strlen(msg));
  56. return 0;
  57. }
  58. static int parse_headers(struct httpd_con *con)
  59. {
  60. char *data = con->req_data;
  61. while ((data = strstr(data, "\r\n")) && data < con->req_data + con->req_size) {
  62. con->req_header_cnt++;
  63. data += 2;
  64. }
  65. con->req_headers = malloc(con->req_header_cnt * sizeof(char *));
  66. if (con->req_headers == NULL)
  67. return -1;
  68. int i = 0;
  69. data = con->req_data;
  70. do {
  71. con->req_headers[i++] = data;
  72. data = strstr(data, "\r\n");
  73. if (data == NULL)
  74. break;
  75. *data++ = '\0';
  76. *data++ = '\0';
  77. } while (data < con->req_data + con->req_size);
  78. return 0;
  79. }
  80. static int parse_args(struct httpd_con *con)
  81. {
  82. /* seperate GET (in req->data) */
  83. char *req = strchr(con->req_data, ' ');
  84. *req++ = '\0';
  85. /* HTTP/1.1 will go to header[0] */
  86. char *tmp = strchr(req, ' ');
  87. *tmp++ = '\0';
  88. con->req_headers[0] = tmp;
  89. /* count args */
  90. tmp = req;
  91. while (*tmp != '\0' && tmp < con->req_data + con->req_size) {
  92. if (*tmp == '?' || *tmp == '&')
  93. con->req_arg_cnt++;
  94. tmp++;
  95. }
  96. con->req_arg_cnt++;
  97. /* alloc args */
  98. con->req_args = malloc(con->req_arg_cnt * sizeof(char *));
  99. if (con->req_args == NULL)
  100. return -1;
  101. int i = 0;
  102. tmp = req;
  103. con->req_args[i++] = tmp;
  104. while (*tmp != '\0' && tmp < con->req_data + con->req_size) {
  105. if (*tmp == '?' || *tmp == '&') {
  106. *tmp++ = '\0';
  107. con->req_args[i++] = tmp;
  108. }
  109. tmp++;
  110. }
  111. return 0;
  112. }
  113. static int httpd_content_handler(int fd, void *privdata)
  114. {
  115. struct httpd_con *con = (struct httpd_con *)privdata;
  116. if (ioctl(fd, FIONREAD, &con->req_size) == -1) {
  117. log_print(LOG_WARN, "http_content_handler(): ioctl(FIONREAD)");
  118. destroy_httpd_con(con);
  119. return -1;
  120. }
  121. con->req_data = malloc(con->req_size);
  122. if (con->req_data == NULL) {
  123. log_print(LOG_WARN, "http_content_handler(): out of memory");
  124. destroy_httpd_con(con);
  125. return -1;
  126. }
  127. con->req_size = read(fd, con->req_data, con->req_size);
  128. if (con->req_size <= 0) {
  129. log_print(LOG_WARN, "http_content_handler(): read()");
  130. destroy_httpd_con(con);
  131. return -1;
  132. }
  133. if (strncmp(con->req_data, "GET ", 4) != 0) {
  134. httpd_send_error(con, "400 Invalid Request", "Not a GET request\r\n");
  135. destroy_httpd_con(con);
  136. return -1;
  137. }
  138. if (parse_headers(con) < 0) {
  139. httpd_send_error(con, "400 Invalid Request", "Error parsing headers\r\n");
  140. destroy_httpd_con(con);
  141. return -1;
  142. }
  143. if (parse_args(con) < 0) {
  144. httpd_send_error(con, "400 Invalid Request", "Error parsing arguments\r\n");
  145. destroy_httpd_con(con);
  146. return -1;
  147. }
  148. struct httpd_callback *entry;
  149. list_for_each_entry(entry, &httpd_cb_list, list) {
  150. if ((entry->wildcard == 1 && strncmp(entry->name, con->req_args[0], strlen(entry->name)) == 0) ||
  151. (entry->wildcard == 0 && strcmp(entry->name, con->req_args[0]) == 0)) {
  152. entry->callback(con, entry->privdata);
  153. destroy_httpd_con(con);
  154. return 0;
  155. }
  156. }
  157. httpd_send_error(con, "404 Not Found", "File not found\r\n");
  158. destroy_httpd_con(con);
  159. return 0;
  160. }
  161. int httpd_accept_handler(int fd, void *privdata)
  162. {
  163. struct httpd_con *con = malloc(sizeof(struct httpd_con));
  164. if (con == NULL) {
  165. log_print(LOG_WARN, "httpd_accept_handler(): out of memory");
  166. return 0;
  167. }
  168. memset(con, 0, sizeof(struct httpd_con));
  169. con->fd = tcp_accept(fd, &con->addr);
  170. if (con->fd < 0) {
  171. free(con);
  172. return 0;
  173. }
  174. con->event = event_add_readfd(NULL, con->fd, httpd_content_handler, con);
  175. return 0;
  176. }
  177. struct httpd_callback * httpd_add_cb(const char *name,
  178. int wildcard,
  179. int (* callback)(struct httpd_con *con, void *privdata),
  180. void *privdata)
  181. {
  182. struct httpd_callback *hcb = malloc(sizeof(struct httpd_callback));
  183. if (hcb == NULL) {
  184. log_print(LOG_WARN, "httpd_create_cb(): out of memory");
  185. return NULL;
  186. }
  187. hcb->name = strdup(name);
  188. hcb->wildcard = wildcard;
  189. hcb->callback = callback;
  190. hcb->privdata = privdata;
  191. list_add_tail(&hcb->list, &httpd_cb_list);
  192. return hcb;
  193. }
  194. int httpd_remove_cb(struct httpd_callback *hcb)
  195. {
  196. list_del(&hcb->list);
  197. free(hcb->name);
  198. free(hcb);
  199. return 0;
  200. }
  201. int httpd_free(void)
  202. {
  203. struct httpd_callback *hcb, *hcb2;
  204. list_for_each_entry_safe(hcb, hcb2, &httpd_cb_list, list)
  205. httpd_remove_cb(hcb);
  206. return 0;
  207. }