serialized LQ data is not always 4 bytes long, so we need a function to precalculate...
[olsrd.git] / src / olsr_comport_http.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41 #include <string.h>
42
43 #include "common/autobuf.h"
44 #include "common/avl.h"
45 #include "olsr_logging.h"
46 #include "olsr_cookie.h"
47 #include "olsr_comport.h"
48 #include "olsr_comport_http.h"
49 #include "olsr_cfg.h"
50
51 #define HTTP_VERSION "HTTP/1.1"
52
53 static struct avl_tree http_handler_tree;
54 static struct olsr_cookie_info *htmlsite_cookie;
55
56 /**Response types */
57 static char http_200_response[] = "OK";
58 static char http_400_response[] = "Bad Request";
59 static char http_401_response[] = "Unauthorized";
60 static char http_403_response[] = "Forbidden";
61 static char http_404_response[] = "Not Found";
62 static char http_413_response[] = "Request Entity Too Large";
63 static char http_501_response[] = "Not Implemented";
64 static char http_503_response[] = "Service Unavailable";
65
66 /* sample for a static html page */
67 static void init_test(void) {
68   static char content[] = "<html><body>Yes, you got it !</body></html>";
69   static char path[] = "/";
70   static char acl[] = "d2lraTpwZWRpYQ=="; /* base 64 .. this is "wikipedia" */
71   static char *aclPtr[] = { acl };
72   struct olsr_html_site *site;
73
74   site = olsr_com_add_htmlsite(path, content, strlen(content));
75   olsr_com_set_htmlsite_acl_auth(site, NULL, 1, aclPtr);
76 }
77
78 void
79 olsr_com_init_http(void) {
80   avl_init(&http_handler_tree, &avl_comp_strcasecmp);
81
82   htmlsite_cookie = olsr_alloc_cookie("comport http sites", OLSR_COOKIE_TYPE_MEMORY);
83   olsr_cookie_set_memory_size(htmlsite_cookie, sizeof(struct olsr_html_site));
84
85   init_test();
86 }
87
88 struct olsr_html_site *
89 olsr_com_add_htmlsite(char *path, char *content, size_t length) {
90   struct olsr_html_site *site;
91
92   site = olsr_cookie_malloc(htmlsite_cookie);
93   site->node.key = strdup(path);
94
95   site->static_site = true;
96   site->site_data = content;
97   site->site_length = length;
98
99   avl_insert(&http_handler_tree, &site->node, AVL_DUP_NO);
100   return site;
101 }
102
103 struct olsr_html_site *
104 olsr_com_add_htmlhandler(void(*sitehandler)(struct autobuf *buf, char *path, int parameter_count, char *parameters[]),
105     char *path) {
106   struct olsr_html_site *site;
107
108   site = olsr_cookie_malloc(htmlsite_cookie);
109   site->node.key = strdup(path);
110
111   site->static_site = false;
112   site->sitehandler = sitehandler;
113
114   avl_insert(&http_handler_tree, &site->node, AVL_DUP_NO);
115   return site;
116 }
117
118 void
119 olsr_com_remove_htmlsite(struct olsr_html_site *site) {
120   avl_delete(&http_handler_tree, &site->node);
121   free(site->node.key);
122   olsr_cookie_free(htmlsite_cookie, site);
123 }
124
125 void
126 olsr_com_set_htmlsite_acl_auth(struct olsr_html_site *site, struct ip_acl *ipacl, int auth_count, char **auth_entries) {
127   site->acl = ipacl;
128   site->auth_count = auth_count;
129   site->auth = auth_entries;
130 }
131
132 /* handle the html site. returns true on successful handling (even if it was unauthorized)
133  * false if we did not find a site
134 */
135 bool
136 olsr_com_handle_htmlsite(struct comport_connection *con, char *path,
137     char *fullpath, int para_count, char **para) {
138   char *str;
139   int i;
140   struct olsr_html_site *site;
141
142   site = (struct olsr_html_site *)avl_find(&http_handler_tree, path);
143   if (site == NULL) {
144     return false;
145   }
146
147   /* check if username/password is necessary */
148   if (site->auth) {
149     /* test for correct ACL */
150     char key[256] = { 0 };
151
152     con->send_as = HTTP_401_UNAUTHORIZED;
153
154     str = strstr(con->in.buf, "\nAuthorization: Basic ");
155     if (str != NULL && sscanf(str + 1, "%*s %*s %s\n", key) == 1) {
156       OLSR_DEBUG(LOG_COMPORT, "ACL string received: %s\n", key);
157       for (i = 0; i < site->auth_count; i++) {
158         if (strcmp(site->auth[i], key) == 0) {
159           con->send_as = HTTP_200_OK;
160           break;
161         }
162       }
163     }
164     if (con->send_as == HTTP_401_UNAUTHORIZED) {
165       return true;
166     }
167   }
168
169   /* check if ip is allowed */
170   if (site->acl != NULL && !ip_acl_acceptable(site->acl, &con->addr, olsr_cnf->ip_version)) {
171     con->send_as = HTTP_403_FORBIDDEN;
172     return true;
173   }
174
175   /* call site handler */
176   if (site->static_site) {
177     abuf_memcpy(&con->out, site->site_data, site->site_length);
178   } else {
179     site->sitehandler(&con->out, fullpath, para_count, para);
180   }
181   con->send_as = HTTP_200_OK;
182   return true;
183 }
184
185 void
186 olsr_com_build_httpheader(struct comport_connection *con) {
187   struct autobuf buf;
188   time_t currtime;
189
190   abuf_init(&buf, 1024);
191
192   abuf_appendf(&buf, "%s %d %s\r\n", HTTP_VERSION, con->send_as, olsr_com_get_http_message(con->send_as));
193
194   /* Date */
195   time(&currtime);
196   abuf_strftime(&buf, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", localtime(&currtime));
197
198   /* Server version */
199   abuf_appendf(&buf, "Server: %s %s %s %s\r\n", olsrd_version, build_date, build_host, HTTP_VERSION);
200
201   /* connection-type */
202   abuf_puts(&buf, "Connection: closed\r\n");
203
204   /* MIME type */
205   abuf_appendf(&buf, "Content-type: text/%s\r\n", con->send_as != HTTP_PLAIN ? "html" : "plain");
206
207   /* Content length */
208   if (con->out.len > 0) {
209     abuf_appendf(&buf, "Content-length: %u\r\n", con->out.len);
210   }
211
212   if (con->send_as == HTTP_401_UNAUTHORIZED) {
213     abuf_appendf(&buf, "WWW-Authenticate: Basic realm=\"%s\"\r\n", "RealmName");
214   }
215   /* Cache-control
216    * No caching dynamic pages
217    */
218   abuf_puts(&buf, "Cache-Control: no-cache\r\n");
219
220   if (con->send_as == HTTP_PLAIN) {
221     abuf_puts(&buf, "Accept-Ranges: bytes\r\n");
222   }
223   /* End header */
224   abuf_puts(&buf, "\r\n");
225
226   abuf_memcpy_prefix(&con->out, buf.buf, buf.len);
227   OLSR_DEBUG(LOG_PLUGINS, "HEADER:\n%s", buf.buf);
228
229   abuf_free(&buf);
230 }
231
232 void
233 olsr_com_create_httperror(struct comport_connection *con) {
234   abuf_appendf(&con->out, "<body><h1>HTTP error %d: %s</h1></body>", con->send_as, olsr_com_get_http_message(con->send_as));
235 }
236
237 char *
238 olsr_com_get_http_message(enum http_header_type type) {
239   static char nothing[] = "";
240
241   switch (type) {
242     case HTTP_PLAIN:
243     case HTTP_200_OK:
244       return http_200_response;
245     case HTTP_400_BAD_REQ:
246       return http_400_response;
247     case HTTP_401_UNAUTHORIZED:
248       return http_401_response;
249     case HTTP_403_FORBIDDEN:
250       return http_403_response;
251     case HTTP_404_NOT_FOUND:
252       return http_404_response;
253     case HTTP_413_REQUEST_TOO_LARGE:
254       return http_413_response;
255     case HTTP_501_NOT_IMPLEMENTED:
256       return http_501_response;
257     case HTTP_503_SERVICE_UNAVAILABLE:
258       return http_503_response;
259     default:
260       return nothing;
261   }
262 }
263
264 void olsr_com_decode_url(char *str) {
265   char *dst = str;
266
267   while (*str) {
268     if (*str == '%') {
269       int value = 0;
270
271       str++;
272       sscanf(str, "%02x", &value);
273       *dst++ = (char) value;
274       str += 2;
275     } else {
276       *dst++ = *str++;
277     }
278   }
279   *dst = 0;
280 }