1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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.
33 #include "http_status.h"
42 /* Plugin data for register */
43 mk_plugin_data_t _shortname
= "palm";
44 mk_plugin_data_t _name
= "Palm";
45 mk_plugin_data_t _version
= "0.1";
46 mk_plugin_stage_t _stages
= MK_PLUGIN_STAGE_10
| MK_PLUGIN_STAGE_40
;
48 /* Read database configuration parameters */
49 int mk_palm_conf(char *confdir
)
55 struct mk_palm
*new, *r
;
56 struct mk_string_line
*line
, *lp
;
58 mk_api
->str_build(&conf_path
, &len
, "%s/palm.conf", confdir
);
60 p
= conf
= mk_api
->config_create(conf_path
);
64 /* Validate palm configuration line */
66 if (strcasecmp(p
->key
, "Palm") == 0) {
67 line
= mk_api
->str_split_line(p
->val
);
73 fprintf(stderr
, MK_PALM_ERROR_LINE
, p
->val
);
80 fprintf(stderr
, MK_PALM_ERROR_LINE
, p
->val
);
87 new = mk_api
->mem_alloc(sizeof(struct mk_palm
));
89 /* Palm file extensions */
90 new->extension
= lp
->val
;
94 new->mimetype
= lp
->val
;
97 /* Palm server address */
98 new->server_addr
= lp
->val
;
101 /* Palm server TCP port */
102 new->server_port
= atoi(lp
->val
);
121 mk_api
->mem_free(conf_path
);
125 struct mk_palm
*mk_palm_get_handler(mk_pointer
* file
)
132 /* looking for extension */
133 while (file
->data
[j
] != '.' && j
>= 0) {
137 extlen
= file
->len
- j
- 1;
144 if (strncasecmp(file
->data
+ j
+ 1, p
->extension
, extlen
) == 0) {
153 void mk_palm_iov_add_header(struct mk_iov
*iov
,
154 mk_pointer header
, mk_pointer value
)
156 mk_api
->iov_add_entry(iov
, header
.data
, header
.len
,
157 mk_iov_equal
, MK_IOV_NOT_FREE_BUF
);
158 mk_api
->iov_add_entry(iov
, value
.data
, value
.len
,
159 mk_iov_crlf
, MK_IOV_NOT_FREE_BUF
);
162 struct mk_iov
*mk_palm_create_env(struct client_request
*cr
,
167 iov
= mk_api
->iov_create(100, 0);
169 mk_api
->iov_add_entry(iov
, sr
->real_path
.data
,
170 sr
->real_path
.len
, mk_iov_crlf
, MK_IOV_NOT_FREE_BUF
);
172 mk_api
->iov_add_entry(iov
, mk_cgi_document_root
.data
,
173 mk_cgi_document_root
.len
,
174 mk_iov_equal
, MK_IOV_NOT_FREE_BUF
);
176 mk_api
->iov_add_entry(iov
, sr
->host_conf
->documentroot
.data
,
177 sr
->host_conf
->documentroot
.len
, mk_iov_crlf
,
178 MK_IOV_NOT_FREE_BUF
);
181 if (sr
->method
== HTTP_METHOD_POST
&& sr
->content_length
> 0) {
182 /* FIX Content length:
183 mk_palm_iov_add_header(iov, mk_cgi_content_length,
186 mk_palm_iov_add_header(iov
, mk_cgi_content_type
, sr
->content_type
);
190 // mk_palm_iov_add_header(iov, mk_cgi_server_addr, mk_api->config->server_addr);
191 mk_palm_iov_add_header(iov
, mk_cgi_server_name
, sr
->host
);
192 mk_palm_iov_add_header(iov
, mk_cgi_server_protocol
, mk_monkey_protocol
);
193 mk_palm_iov_add_header(iov
, mk_cgi_server_software
,
194 mk_api
->config
->server_software
);
195 //mk_palm_iov_add_header(iov, mk_cgi_server_signature, sr->host_conf->host_signature);
197 if (sr
->user_agent
.data
)
198 mk_palm_iov_add_header(iov
, mk_cgi_http_user_agent
, sr
->user_agent
);
201 mk_palm_iov_add_header(iov
, mk_cgi_http_accept
, sr
->accept
);
203 if (sr
->accept_charset
.data
)
204 mk_palm_iov_add_header(iov
, mk_cgi_http_accept_charset
,
207 if (sr
->accept_encoding
.data
)
208 mk_palm_iov_add_header(iov
, mk_cgi_http_accept_encoding
,
209 sr
->accept_encoding
);
211 if (sr
->accept_language
.data
)
212 mk_palm_iov_add_header(iov
, mk_cgi_http_accept_language
,
213 sr
->accept_language
);
216 mk_palm_iov_add_header(iov
, mk_cgi_http_host
, sr
->host
);
218 if (sr
->cookies
.data
)
219 mk_palm_iov_add_header(iov
, mk_cgi_http_cookie
, sr
->cookies
);
221 if (sr
->referer
.data
)
222 mk_palm_iov_add_header(iov
, mk_cgi_http_referer
, sr
->referer
);
224 // mk_palm_iov_add_header(iov, mk_cgi_server_port, mk_monkey_port);
225 mk_palm_iov_add_header(iov
, mk_cgi_gateway_interface
, mk_cgi_version
);
226 //mk_palm_iov_add_header(iov, mk_cgi_remote_addr, cr->ip);
227 mk_palm_iov_add_header(iov
, mk_cgi_request_uri
, sr
->uri
);
228 //mk_palm_iov_add_header(iov, mk_cgi_request_method, sr->method);
229 mk_palm_iov_add_header(iov
, mk_cgi_script_name
, sr
->uri
);
232 /* real path is not an mk_pointer */
233 mk_palm_iov_add_header(iov
, mk_cgi_script_filename
, sr
->real_path
);
234 //mk_palm_iov_add_header(iov, mk_cgi_remote_port, cr->port);
235 mk_palm_iov_add_header(iov
, mk_cgi_query_string
, sr
->query_string
);
236 //mk_palm_iov_add_header(iov, mk_cgi_post_vars, sr->post_variables);
239 mk_api
->iov_add_entry(iov
, mk_iov_crlf
.data
, mk_iov_crlf
.len
,
240 mk_iov_none
, MK_IOV_NOT_FREE_BUF
);
241 mk_api
->iov_add_entry(iov
, mk_iov_crlf
.data
, mk_iov_crlf
.len
,
242 mk_iov_none
, MK_IOV_NOT_FREE_BUF
);
243 mk_api
->iov_add_entry(iov
, mk_iov_crlf
.data
, mk_iov_crlf
.len
,
244 mk_iov_none
, MK_IOV_NOT_FREE_BUF
);
249 int mk_palm_send_response(struct client_request *cr, struct request *sr,
256 char *status_msg = "Status: ";
259 if (strncasecmp(buf, status_msg, len) == 0) {
260 i = (int) mk_api->str_search(buf + len, " ");
261 s = mk_api->str_copy_substr(buf, len, len + i);
262 sr->headers->status = atoi(s);
263 i = (int) mk_api->str_search(buf, mk_crlf.data) + mk_crlf.len;
267 sr->headers->status = M_HTTP_OK;
270 sr->headers->cgi = SH_CGI;
271 sr->headers->content_length = 0;
273 mk_api->socket_cork_flag(cr->socket, TCP_CORK_ON);
274 mk_api->header_send(cr->socket, cr, sr, sr->log);
275 n = write(cr->socket, buf + i, strlen(buf + i));
280 int _mk_plugin_init(void **api
, char *confdir
)
285 /* Init some pointers */
286 mk_api
->pointer_set(&mk_monkey_protocol
, HTTP_PROTOCOL_11_STR
);
287 mk_api
->pointer_set(&mk_iov_crlf
, MK_IOV_CRLF
);
288 mk_api
->pointer_set(&mk_iov_equal
, MK_IOV_EQUAL
);
290 /* Read configuration */
291 mk_palm_conf(confdir
);
295 int _mk_plugin_stage_10(struct server_config
*config
)
301 int _mk_plugin_stage_40(struct plugin
*plugin
, struct client_request
*cr
, struct request
*sr
)
303 struct mk_palm
*palm
;
304 struct mk_palm_request
*pr
;
306 PLUGIN_TRACE("PALM STAGE 40");
307 PLUGIN_TRACE("real_path:'%s'", sr
->real_path
.data
);
309 palm
= mk_palm_get_handler(&sr
->uri
);
311 return MK_PLUGIN_RET_NOT_ME
;
314 /* Connect to server */
315 pr
= mk_palm_do_instance(palm
, cr
, sr
);
318 PLUGIN_TRACE("return %i (MK_PLUGIN_RET_END)", MK_PLUGIN_RET_END
);
319 return MK_PLUGIN_RET_END
;
322 /* Register Palm instance */
323 mk_palm_request_add(pr
);
325 /* Register socket with thread Epoll interface */
326 mk_api
->event_add(pr
->palm_fd
, plugin
, cr
, sr
);
327 PLUGIN_TRACE("Palm: Event registered / client=%i / palm_socket=%i",
328 pr
->client_fd
, pr
->palm_fd
);
331 PLUGIN_TRACE("return %i (MK_PLUGIN_RET_CONTINUE)", MK_PLUGIN_RET_CONTINUE
);
332 return MK_PLUGIN_RET_CONTINUE
;
335 struct mk_palm_request
*mk_palm_request_create(int client_fd
,
337 struct client_request
*cr
,
339 struct mk_palm
*palm
)
341 struct mk_palm_request
*new;
343 new = mk_api
->mem_alloc(sizeof(struct mk_palm_request
));
344 new->client_fd
= client_fd
;
345 new->palm_fd
= palm_fd
;
349 new->headers_sent
= VAR_OFF
;
357 struct mk_palm_request
*mk_palm_do_instance(struct mk_palm
*palm
,
358 struct client_request
*cr
, struct request
*sr
)
363 /* Get Palm handler */
364 palm
= mk_palm_get_handler(&sr
->uri
);
366 /* Connecting to Palm Server */
367 palm_socket
= (int) mk_api
->socket_create();
368 ret
= (int) mk_api
->socket_connect(palm_socket
,
373 fprintf(stderr
, "\nPalm: Cannot connect to %s on port %i",
374 palm
->server_addr
, palm
->server_port
);
377 /* Set palm socket to non-blocking */
378 mk_api
->socket_set_nonblocking(palm_socket
);
380 /* Return instance */
381 return mk_palm_request_create(cr
->socket
, palm_socket
, cr
, sr
, palm
);
384 void mk_palm_request_add(struct mk_palm_request
*pr
)
386 struct mk_palm_request
*pr_list
, *aux
;
388 /* Get thread data */
389 pr_list
= pthread_getspecific(_mk_plugin_data
);
391 /* No connection previously was found */
393 pthread_setspecific(_mk_plugin_data
, pr
);
404 pthread_setspecific(_mk_plugin_data
, pr_list
);
407 /* It register the request and connection data, if it doesn't
408 * exists it will be create it, otherwise will return the pointer
409 * to the mk_palm_request struct node
411 struct mk_palm_request
*mk_palm_request_get(int socket
)
413 struct mk_palm_request
*pr
, *aux
;
415 /* Get thread data */
416 pr
= pthread_getspecific(_mk_plugin_data
);
418 /* No connection previously was found */
426 if(aux
->client_fd
== socket
){
435 void mk_palm_request_update(int socket
, struct mk_palm_request
*pr
)
437 struct mk_palm_request
*aux
, *list
;
439 list
= pthread_getspecific(_mk_plugin_data
);
447 if (aux
->client_fd
== socket
) {
448 aux
->bytes_sent
= pr
->bytes_sent
;
449 aux
->bytes_read
= pr
->bytes_read
;
450 aux
->headers_sent
= pr
->headers_sent
;
453 pthread_setspecific(_mk_plugin_data
, list
);
460 void _mk_plugin_stage_40_event_write(struct client_request
*cr
, struct request
*sr
)
463 ssize_t bytes_iov
=-1;
465 struct mk_palm_request
*pr
;
467 PLUGIN_TRACE("Handling write event");
469 pr
= mk_palm_request_get(cr
->socket
);
471 if (pr
->bytes_sent
== 0) {
473 PLUGIN_TRACE("Palm request: '%s'", sr
->real_path
.data
);
475 /* Palm environment vars */
476 iov
= mk_palm_create_env(cr
, sr
);
478 /* Setup Palm socket */
479 mk_api
->socket_set_tcp_nodelay(pr
->palm_fd
);
480 /* Write request to palm server */
481 bytes_iov
= (ssize_t
)mk_api
->iov_send(pr
->palm_fd
, iov
, MK_IOV_SEND_TO_SOCKET
);
484 pr
->bytes_sent
+= bytes_iov
;
485 n
= (long) bytes_iov
;
490 PLUGIN_TRACE("Read: %i Write: %i", pr
->bytes_read
, pr
->bytes_sent
);
491 mk_api
->event_socket_change_mode(pr
->palm_fd
, MK_EPOLL_READ
);
495 int _mk_plugin_stage_40_event_read(struct client_request
*cr
, struct request
*sr
)
503 struct mk_palm_request
*pr
;
505 pr
= mk_palm_request_get(cr
->socket
);
508 PLUGIN_TRACE("Invalid palm request, not found");
512 PLUGIN_TRACE("Reading data from FD %i", pr
->palm_fd
);
514 /* Reset read buffer */
515 bzero(pr
->data_read
, MK_PALM_BUFFER_SIZE
);
519 pr
->n_read
= read(pr
->palm_fd
, pr
->data_read
, (MK_PALM_BUFFER_SIZE
- 1));
521 if (pr
->n_read
< 0) {
525 PLUGIN_TRACE("Bytes read %i", pr
->n_read
);
527 if (pr
->n_read
>=0) {
528 if (pr
->headers_sent
== VAR_OFF
) {
529 PLUGIN_TRACE("Sending headers");
531 sr
->headers
->status
= M_HTTP_OK
;
532 sr
->headers
->cgi
= SH_CGI
;
534 /* Chunked transfer encoding */
535 if (sr
->protocol
>= HTTP_PROTOCOL_11
) {
536 sr
->headers
->transfer_encoding
= MK_HEADER_TE_TYPE_CHUNKED
;
539 /* Look for headers end */
540 headers_end
= (int) mk_api
->str_search(pr
->buffer
, MK_IOV_CRLFCRLF
);
542 PLUGIN_TRACE("Headers end %i", headers_end
);
544 if (headers_end
> 0) {
548 /* Send just headers from buffer */
549 n_header
= (int) mk_api
->header_send(cr
->socket
, cr
, sr
, sr
->log
);
550 write(cr
->socket
, pr
->buffer
, headers_end
);
552 /* Send first chunk data */
553 mk_api
->str_build(&chunk_size
, &len
, "%x%s", n
, MK_CRLF
);
555 a
= write(cr
->socket
, chunk_size
, len
);
557 PLUGIN_TRACE("first write: %i bytes", a
);
559 n
= write(cr
->socket
, pr
->buffer
+ headers_end
, n
- headers_end
);
561 PLUGIN_TRACE("second write: %i bytes", n
);
563 /* Turn off TCP_CORK_OFF */
564 mk_api
->socket_cork_flag(cr
->socket
, TCP_CORK_OFF
);
565 pr
->bytes_sent_to_client
= 1;
570 PLUGIN_TRACE("Just N: %i", n
);
571 PLUGIN_TRACE("Total read from palm server: %i", pr
->bytes_read
);
573 //n = send(0, pr->buffer, n, 0);
576 l
= (int) mk_api
->str_build(&chunk_size
, &len
,"%x%s", n
, MK_CRLF
);
577 PLUGIN_TRACE("chunk: %s (len: %i)", chunk_size
, len
);
579 write(cr
->socket
, chunk_size
, l
);
580 n
= write(pr
->client_fd
, pr
->buffer
, n
);
585 PLUGIN_TRACE("Bytes sent to client %i: %i", pr
->client_fd
, n
);
587 ret
= MK_PLUGIN_RET_CONTINUE
;
592 PLUGIN_TRACE("BIG ERROR!");
595 write(cr
->socket
, MK_CRLF
, 2);
597 mk_api
->mem_free(chunk_size
);
600 /* Update thread node info */
601 mk_palm_request_update(cr
->socket
, pr
);