Fix 64 bits warnings and issues
[MonkeyD.git] / plugins / palm / palm.c
blob621cf5df29d0df4a04de27d7d3aa2d14212db079
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /* Monkey HTTP Daemon
4 * ------------------
5 * Copyright (C) 2001-2010, Eduardo Silva P.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
28 #include "config.h"
29 #include "plugin.h"
30 #include "str.h"
31 #include "http.h"
32 #include "http_status.h"
33 #include "monkey.h"
34 #include "epoll.h"
35 #include "utils.h"
36 #include "header.h"
38 #include "cgi.h"
39 #include "palm.h"
40 #include "request.h"
43 /* Plugin data for register */
44 mk_plugin_data_t _shortname = "palm";
45 mk_plugin_data_t _name = "Palm";
46 mk_plugin_data_t _version = "0.11.0";
47 mk_plugin_hook_t _hooks = MK_PLUGIN_STAGE_30;
50 /* Read database configuration parameters */
51 int mk_palm_conf(char *confdir)
53 int ret = 0;
54 unsigned long len;
55 char *conf_path;
56 struct mk_palm *new, *r;
57 struct mk_config_section *section;
59 /* Read palm configuration file */
60 mk_api->str_build(&conf_path, &len, "%s/palm.conf", confdir);
61 conf = mk_api->config_create(conf_path);
62 section = conf->section;
64 r = palms;
65 while (section) {
66 /* Just read PALM sections */
67 if (strcasecmp(section->name, "PALM") != 0) {
68 section = section->next;
69 continue;
72 /* Alloc node */
73 new = mk_api->mem_alloc(sizeof(struct mk_palm));
75 /* Palm file extensions */
76 new->extension = mk_api->config_section_getval(section, "Extension",
77 MK_CONFIG_VAL_STR);
78 /* Palm mime type */
79 new->mimetype = mk_api->config_section_getval(section, "Mimetype",
80 MK_CONFIG_VAL_STR);
81 /* Palm server address */
82 new->server_addr = mk_api->config_section_getval(section, "ServerAddr",
83 MK_CONFIG_VAL_STR);
84 /* Palm server TCP port */
85 new->server_port = (size_t) mk_api->config_section_getval(section, "ServerPort",
86 MK_CONFIG_VAL_NUM);
88 #ifdef TRACE
89 PLUGIN_TRACE("RegPalm '%s|%s|%s|%i'", new->extension, new->mimetype,
90 new->server_addr, new->server_port);
91 #endif
93 new->next = NULL;
95 /* Linking node */
96 if (!palms) {
97 palms = new;
99 else {
100 r = palms;
101 while (r->next) {
102 r = r->next;
104 r->next = new;
106 section = section->next;
109 mk_api->mem_free(conf_path);
110 return ret;
113 struct mk_palm *mk_palm_get_handler(mk_pointer * file)
115 struct mk_palm *p;
116 int j, len, extlen;
118 j = len = file->len;
120 /* looking for extension */
121 while (file->data[j] != '.' && j >= 0) {
122 j--;
125 extlen = file->len - j - 1;
126 if (j == 0) {
127 return NULL;
130 p = palms;
131 while (p) {
132 if (strncasecmp(file->data + j + 1, p->extension, extlen) == 0) {
133 return p;
135 p = p->next;
138 return NULL;
141 void mk_palm_iov_add_header(struct mk_iov *iov,
142 mk_pointer header, mk_pointer value)
144 mk_api->iov_add_entry(iov, header.data, header.len,
145 mk_iov_equal, MK_IOV_NOT_FREE_BUF);
146 mk_api->iov_add_entry(iov, value.data, value.len,
147 mk_iov_crlf, MK_IOV_NOT_FREE_BUF);
150 struct mk_iov *mk_palm_create_env(struct client_request *cr,
151 struct request *sr)
153 struct mk_iov *iov;
155 iov = mk_api->iov_create(100, 0);
156 #ifdef TRACE
157 PLUGIN_TRACE( "Create environment for palm server");
158 #endif
159 mk_api->iov_add_entry(iov, sr->real_path.data,
160 sr->real_path.len, mk_iov_crlf, MK_IOV_NOT_FREE_BUF);
162 mk_api->iov_add_entry(iov, mk_cgi_document_root.data,
163 mk_cgi_document_root.len,
164 mk_iov_equal, MK_IOV_NOT_FREE_BUF);
166 mk_api->iov_add_entry(iov, sr->host_conf->documentroot.data,
167 sr->host_conf->documentroot.len, mk_iov_crlf,
168 MK_IOV_NOT_FREE_BUF);
170 // mk_palm_iov_add_header(iov, mk_cgi_server_addr, mk_api->config->server_addr);
171 mk_palm_iov_add_header(iov, mk_cgi_server_name, sr->host);
172 mk_palm_iov_add_header(iov, mk_cgi_server_protocol, mk_monkey_protocol);
173 mk_palm_iov_add_header(iov, mk_cgi_server_software,
174 mk_api->config->server_software);
175 //mk_palm_iov_add_header(iov, mk_cgi_server_signature, sr->host_conf->host_signature);
177 if (sr->user_agent.data)
178 mk_palm_iov_add_header(iov, mk_cgi_http_user_agent, sr->user_agent);
180 if (sr->accept.data)
181 mk_palm_iov_add_header(iov, mk_cgi_http_accept, sr->accept);
183 if (sr->accept_charset.data)
184 mk_palm_iov_add_header(iov, mk_cgi_http_accept_charset,
185 sr->accept_charset);
187 if (sr->accept_encoding.data)
188 mk_palm_iov_add_header(iov, mk_cgi_http_accept_encoding,
189 sr->accept_encoding);
191 if (sr->accept_language.data)
192 mk_palm_iov_add_header(iov, mk_cgi_http_accept_language,
193 sr->accept_language);
195 if (sr->host.data)
196 mk_palm_iov_add_header(iov, mk_cgi_http_host, sr->host);
198 if (sr->cookies.data)
199 mk_palm_iov_add_header(iov, mk_cgi_http_cookie, sr->cookies);
201 if (sr->referer.data)
202 mk_palm_iov_add_header(iov, mk_cgi_http_referer, sr->referer);
204 // mk_palm_iov_add_header(iov, mk_cgi_server_port, mk_monkey_port);
205 mk_palm_iov_add_header(iov, mk_cgi_gateway_interface, mk_cgi_version);
206 //mk_palm_iov_add_header(iov, mk_cgi_remote_addr, cr->ip);
207 mk_palm_iov_add_header(iov, mk_cgi_request_uri, sr->uri);
208 mk_palm_iov_add_header(iov, mk_cgi_request_method, sr->method_p);
209 mk_palm_iov_add_header(iov, mk_cgi_script_name, sr->uri);
212 /* real path is not an mk_pointer */
213 mk_palm_iov_add_header(iov, mk_cgi_script_filename, sr->real_path);
214 //mk_palm_iov_add_header(iov, mk_cgi_remote_port, cr->port);
215 mk_palm_iov_add_header(iov, mk_cgi_query_string, sr->query_string);
216 mk_palm_iov_add_header(iov, mk_cgi_post_vars, sr->post_variables);
218 if (sr->method == HTTP_METHOD_POST && sr->content_length > 0) {
219 /* Content length */
220 mk_pointer p;
221 unsigned long len;
222 char *length = 0;
223 mk_api->str_build(&length, &len, "%i", sr->content_length);
224 p.data = length;
225 p.len = len;
227 mk_palm_iov_add_header(iov, mk_cgi_content_length, p);
228 mk_palm_iov_add_header(iov, mk_cgi_content_type, sr->content_type);
231 /* CRLF */
232 mk_api->iov_add_entry(iov, mk_iov_crlf.data, mk_iov_crlf.len,
233 mk_iov_none, MK_IOV_NOT_FREE_BUF);
234 mk_api->iov_add_entry(iov, mk_iov_crlf.data, mk_iov_crlf.len,
235 mk_iov_none, MK_IOV_NOT_FREE_BUF);
236 mk_api->iov_add_entry(iov, mk_iov_crlf.data, mk_iov_crlf.len,
237 mk_iov_none, MK_IOV_NOT_FREE_BUF);
238 return iov;
242 int mk_palm_send_headers(struct client_request *cr, struct request *sr)
244 int n;
246 sr->headers->status = M_HTTP_OK;
247 sr->headers->cgi = SH_CGI;
249 /* Chunked transfer encoding */
250 if (sr->protocol >= HTTP_PROTOCOL_11) {
251 sr->headers->transfer_encoding = MK_HEADER_TE_TYPE_CHUNKED;
254 /* Send just headers from buffer */
255 #ifdef TRACE
256 PLUGIN_TRACE("[FD %i] Sending headers", cr->socket);
257 #endif
258 n = (int) mk_api->header_send(cr->socket, cr, sr);
260 /* Monkey core send_headers set TCP_CORK_ON, we need to get
261 * back the status to OFF
263 mk_api->socket_cork_flag(cr->socket, TCP_CORK_OFF);
264 #ifdef TRACE
265 PLUGIN_TRACE("[FD %i] Send headers returned %i", cr->socket, n);
266 #endif
268 return n;
272 int _mkp_init(void **api, char *confdir)
274 mk_api = *api;
275 palms = 0;
277 /* Init some pointers */
278 mk_api->pointer_set(&mk_monkey_protocol, HTTP_PROTOCOL_11_STR);
279 mk_api->pointer_set(&mk_iov_crlf, MK_IOV_CRLF);
280 mk_api->pointer_set(&mk_iov_equal, MK_IOV_EQUAL);
282 /* Read configuration */
283 mk_palm_conf(confdir);
285 /* Init CGI memory buffers */
286 mk_cgi_env();
288 return 0;
291 void _mkp_exit()
295 int _mkp_stage_30(struct plugin *plugin, struct client_request *cr, struct request *sr)
297 struct mk_palm *palm;
298 struct mk_palm_request *pr;
300 #ifdef TRACE
301 PLUGIN_TRACE("PALM STAGE 30, requesting '%s'", sr->real_path.data);
302 #endif
304 palm = mk_palm_get_handler(&sr->real_path);
305 if (!palm || !sr->file_info) {
306 #ifdef TRACE
307 PLUGIN_TRACE("[FD %i] Not handled by me", cr->socket);
308 #endif
310 return MK_PLUGIN_RET_NOT_ME;
313 /* Connect to server */
314 pr = mk_palm_do_instance(palm, cr, sr);
316 if (!pr) {
317 #ifdef TRACE
318 PLUGIN_TRACE("return %i (MK_PLUGIN_RET_END)", MK_PLUGIN_RET_END);
319 #endif
321 return MK_PLUGIN_RET_END;
324 /* Register Palm instance */
325 mk_palm_request_add(pr);
327 /* Register socket with thread Epoll interface */
328 mk_api->event_add(pr->palm_fd, MK_EPOLL_READ, plugin, cr, sr);
329 #ifdef TRACE
330 PLUGIN_TRACE("Palm: Event registered for palm_socket=%i", pr->palm_fd);
331 #endif
333 /* Send request */
334 mk_palm_send_request(cr, sr);
335 mk_palm_send_headers(cr, sr);
337 #ifdef TRACE
338 PLUGIN_TRACE("return %i (MK_PLUGIN_RET_CONTINUE)", MK_PLUGIN_RET_CONTINUE);
339 #endif
341 return MK_PLUGIN_RET_CONTINUE;
346 struct mk_palm_request *mk_palm_do_instance(struct mk_palm *palm,
347 struct client_request *cr,
348 struct request *sr)
350 int ret;
351 int palm_socket;
353 /* Connecting to Palm Server */
354 palm_socket = mk_api->socket_create();
355 ret = mk_api->socket_connect(palm_socket,
356 palm->server_addr,
357 palm->server_port);
359 if (ret < 0) {
360 fprintf(stderr, "\nPalm: Cannot connect to %s on port %i",
361 palm->server_addr, palm->server_port);
362 mk_api->header_set_http_status(sr, M_SERVER_INTERNAL_ERROR);
363 return NULL;
366 /* Return instance */
367 return mk_palm_request_create(cr->socket, palm_socket, cr, sr, palm);
370 void mk_palm_send_request(struct client_request *cr, struct request *sr)
372 int n;
373 ssize_t bytes_iov=-1;
374 struct mk_iov *iov;
375 struct mk_palm_request *pr;
377 #ifdef TRACE
378 PLUGIN_TRACE("Sending request to Palm Server");
379 #endif
381 pr = mk_palm_request_get_by_http(cr->socket);
382 if (pr) {
383 if (pr->bytes_sent == 0) {
385 #ifdef TRACE
386 PLUGIN_TRACE("Palm request: '%s'", sr->real_path.data);
387 #endif
388 /* Palm environment vars */
389 iov = mk_palm_create_env(cr, sr);
391 /* Write request to palm server */
392 bytes_iov = (ssize_t )mk_api->iov_send(pr->palm_fd, iov, MK_IOV_SEND_TO_SOCKET);
394 if (bytes_iov >= 0){
395 pr->bytes_sent += bytes_iov;
396 n = (long) bytes_iov;
399 /* Socket stuff */
400 mk_api->socket_set_nonblocking(pr->palm_fd);
404 #ifdef TRACE
405 PLUGIN_TRACE("Bytes sent to PALM SERVER: %i", pr->bytes_sent);
406 #endif
409 int mk_palm_send_chunk(int socket, void *buffer, unsigned int len)
411 int n;
412 char *chunk_size=0;
413 unsigned long chunk_len=0;
416 mk_api->socket_cork_flag(socket, TCP_CORK_ON);
417 mk_api->str_build(&chunk_size, &chunk_len, "%x%s", len, MK_CRLF);
418 n = mk_api->socket_send(socket, chunk_size, chunk_len);
419 mk_api->mem_free(chunk_size);
421 if (n < 0) {
422 #ifdef TRACE
423 PLUGIN_TRACE("Error sending chunked header, socket_send() returned %i", n);
424 #endif
425 perror("socket_send");
426 return -1;
429 n = mk_api->socket_send(socket, buffer, len);
430 #ifdef TRACE
431 PLUGIN_TRACE("SEND CHUNK: requested %i, sent %i", len, n);
432 #endif
434 if (n < 0) {
435 #ifdef TRACE
436 PLUGIN_TRACE("Error sending chunked body, socket_send() returned %i", n);
437 perror("socket_send");
438 #endif
439 return -1;
442 mk_api->socket_send(socket, MK_CRLF, 2);
443 mk_api->socket_cork_flag(socket, TCP_CORK_OFF);
444 return n;
447 int mk_palm_send_end_chunk(int socket)
449 int n;
451 n = mk_api->socket_send(socket, "0\r\n\r\n", 5);
452 return n;
455 int _mkp_event_read(int sockfd)
457 int n;
458 int ret = -1;
459 int headers_end = -1;
460 int read_offset = 0;
461 struct mk_palm_request *pr;
463 pr = mk_palm_request_get(sockfd);
465 if (!pr){
466 #ifdef TRACE
467 PLUGIN_TRACE("Invalid palm request, not found");
468 #endif
469 return -1;
472 /* Reset read buffer */
473 bzero(pr->data_read, MK_PALM_BUFFER_SIZE);
475 /* Read data */
476 pr->len_read = mk_api->socket_read(pr->palm_fd,
477 pr->data_read,
478 (MK_PALM_BUFFER_SIZE - 1));
480 #ifdef TRACE
481 PLUGIN_TRACE("FD %i", sockfd);
482 PLUGIN_TRACE(" socket read : %i", pr->len_read);
483 PLUGIN_TRACE(" headers sent : %i", pr->headers_sent);
484 #endif
486 if (pr->len_read <= 0) {
487 #ifdef TRACE
488 PLUGIN_TRACE("Ending connection: read() = %i", pr->len_read);
489 #endif
490 if (pr->sr->protocol >= HTTP_PROTOCOL_11) {
491 n = mk_palm_send_end_chunk(pr->client_fd);
494 return MK_PLUGIN_RET_END;
496 else if (pr->len_read > 0) {
497 if (pr->headers_sent == VAR_OFF) {
498 headers_end = mk_api->str_search(pr->data_read,
499 MK_IOV_CRLFCRLF);
500 if (headers_end == -1) {
501 headers_end = mk_api->str_search(pr->data_read,
502 MK_IOV_LFLFLFLF);
505 /* Look for headers end */
506 while (headers_end == -1) {
507 #ifdef TRACE
508 PLUGIN_TRACE("CANNOT FIND HEADERS_END in FD %i", pr->palm_fd);
509 #endif
510 n = mk_api->socket_read(pr->palm_fd,
511 pr->data_read + pr->len_read,
512 (MK_PALM_BUFFER_SIZE -1) - pr->len_read);
514 if (n > 0) {
515 pr->len_read += n;
517 else{
518 #ifdef TRACE
519 PLUGIN_TRACE("[FD %i] N READ: %i", pr->palm_fd, n);
520 PLUGIN_TRACE("********* FIXME ***********\n%s", pr->data_read);
521 // exit(1);
522 #endif
525 headers_end = (int) mk_api->str_search(pr->data_read,
526 MK_IOV_CRLFCRLF);
529 if (headers_end > 0) {
530 headers_end += 4;
532 else {
533 #ifdef TRACE
534 PLUGIN_TRACE("SOMETHING BAD HAPPENS");
535 #endif
538 /* FIXME: What about if this socket_send wrote partial headers ? ugh! */
539 n = mk_api->socket_send(pr->client_fd, pr->data_read, headers_end);
541 #ifdef TRACE
542 PLUGIN_TRACE("Headers sent to HTTP client: %i", n);
543 #endif
545 /* Enable headers flag */
546 pr->headers_sent = VAR_ON;
547 read_offset = headers_end;
550 int sent = 0;
551 while (sent != (pr->len_read - read_offset)) {
552 #ifdef TRACE
553 PLUGIN_TRACE("LOOP");
554 #endif
555 if (pr->sr->protocol >= HTTP_PROTOCOL_11) {
556 n = mk_palm_send_chunk(pr->client_fd,
557 pr->data_read + read_offset + sent,
558 pr->len_read - read_offset - sent);
560 else {
561 n = mk_api->socket_send(pr->client_fd,
562 pr->data_read + read_offset + sent,
563 pr->len_read - read_offset - sent);
566 if (n < 0) {
567 #ifdef TRACE
568 PLUGIN_TRACE("WRITE ERROR");
569 #endif
570 perror("socket_send");
571 return MK_PLUGIN_RET_END;
573 else {
574 #ifdef TRACE
575 PLUGIN_TRACE("BYTES SENT: %i", n);
576 #endif
577 sent += n;
581 mk_api->socket_cork_flag(pr->client_fd, TCP_CORK_OFF);
582 ret = MK_PLUGIN_RET_CONTINUE;
584 mk_palm_request_update(sockfd, pr);
586 else {
587 #ifdef TRACE
588 PLUGIN_TRACE("FIXME!, this should not happend");
589 #endif
592 /* Update thread node info */
593 mk_palm_request_update(sockfd, pr);
595 return ret;
598 /* sockfd = palm_fd */
599 int hangup(int sockfd)
601 struct mk_palm_request *pr;
603 #ifdef TRACE
604 PLUGIN_TRACE("[FD %i] hangup", sockfd);
605 #endif
607 pr = mk_palm_request_get(sockfd) ;
608 if (!pr) {
609 return MK_PLUGIN_RET_END;
612 mk_api->socket_close(pr->palm_fd);
613 mk_api->event_del(pr->palm_fd);
614 mk_api->http_request_end(pr->client_fd);
615 mk_palm_free_request(pr->palm_fd);
617 return MK_PLUGIN_RET_END;
620 int _mkp_event_close(int sockfd)
622 #ifdef TRACE
623 PLUGIN_TRACE("[FD %i] event close", sockfd);
624 #endif
626 return hangup(sockfd);
629 int _mkp_event_error(int sockfd)
631 #ifdef TRACE
632 PLUGIN_TRACE("[FD %i] event error", sockfd);
633 #endif
635 return hangup(sockfd);