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.
32 #include "http_status.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
)
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
;
66 /* Just read PALM sections */
67 if (strcasecmp(section
->name
, "PALM") != 0) {
68 section
= section
->next
;
73 new = mk_api
->mem_alloc(sizeof(struct mk_palm
));
75 /* Palm file extensions */
76 new->extension
= mk_api
->config_section_getval(section
, "Extension",
79 new->mimetype
= mk_api
->config_section_getval(section
, "Mimetype",
81 /* Palm server address */
82 new->server_addr
= mk_api
->config_section_getval(section
, "ServerAddr",
84 /* Palm server TCP port */
85 new->server_port
= (size_t) mk_api
->config_section_getval(section
, "ServerPort",
89 PLUGIN_TRACE("RegPalm '%s|%s|%s|%i'", new->extension
, new->mimetype
,
90 new->server_addr
, new->server_port
);
106 section
= section
->next
;
109 mk_api
->mem_free(conf_path
);
113 struct mk_palm
*mk_palm_get_handler(mk_pointer
* file
)
120 /* looking for extension */
121 while (file
->data
[j
] != '.' && j
>= 0) {
125 extlen
= file
->len
- j
- 1;
132 if (strncasecmp(file
->data
+ j
+ 1, p
->extension
, extlen
) == 0) {
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
,
155 iov
= mk_api
->iov_create(100, 0);
157 PLUGIN_TRACE( "Create environment for palm server");
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
);
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
,
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
);
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) {
223 mk_api
->str_build(&length
, &len
, "%i", sr
->content_length
);
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
);
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
);
242 int mk_palm_send_headers(struct client_request
*cr
, struct request
*sr
)
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 */
256 PLUGIN_TRACE("[FD %i] Sending headers", cr
->socket
);
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
);
265 PLUGIN_TRACE("[FD %i] Send headers returned %i", cr
->socket
, n
);
272 int _mkp_init(void **api
, char *confdir
)
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 */
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
;
301 PLUGIN_TRACE("PALM STAGE 30, requesting '%s'", sr
->real_path
.data
);
304 palm
= mk_palm_get_handler(&sr
->real_path
);
305 if (!palm
|| !sr
->file_info
) {
307 PLUGIN_TRACE("[FD %i] Not handled by me", cr
->socket
);
310 return MK_PLUGIN_RET_NOT_ME
;
313 /* Connect to server */
314 pr
= mk_palm_do_instance(palm
, cr
, sr
);
318 PLUGIN_TRACE("return %i (MK_PLUGIN_RET_END)", MK_PLUGIN_RET_END
);
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
);
330 PLUGIN_TRACE("Palm: Event registered for palm_socket=%i", pr
->palm_fd
);
334 mk_palm_send_request(cr
, sr
);
335 mk_palm_send_headers(cr
, sr
);
338 PLUGIN_TRACE("return %i (MK_PLUGIN_RET_CONTINUE)", MK_PLUGIN_RET_CONTINUE
);
341 return MK_PLUGIN_RET_CONTINUE
;
346 struct mk_palm_request
*mk_palm_do_instance(struct mk_palm
*palm
,
347 struct client_request
*cr
,
353 /* Connecting to Palm Server */
354 palm_socket
= mk_api
->socket_create();
355 ret
= mk_api
->socket_connect(palm_socket
,
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
);
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
)
373 ssize_t bytes_iov
=-1;
375 struct mk_palm_request
*pr
;
378 PLUGIN_TRACE("Sending request to Palm Server");
381 pr
= mk_palm_request_get_by_http(cr
->socket
);
383 if (pr
->bytes_sent
== 0) {
386 PLUGIN_TRACE("Palm request: '%s'", sr
->real_path
.data
);
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
);
395 pr
->bytes_sent
+= bytes_iov
;
396 n
= (long) bytes_iov
;
400 mk_api
->socket_set_nonblocking(pr
->palm_fd
);
405 PLUGIN_TRACE("Bytes sent to PALM SERVER: %i", pr
->bytes_sent
);
409 int mk_palm_send_chunk(int socket
, void *buffer
, unsigned int len
)
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
);
423 PLUGIN_TRACE("Error sending chunked header, socket_send() returned %i", n
);
425 perror("socket_send");
429 n
= mk_api
->socket_send(socket
, buffer
, len
);
431 PLUGIN_TRACE("SEND CHUNK: requested %i, sent %i", len
, n
);
436 PLUGIN_TRACE("Error sending chunked body, socket_send() returned %i", n
);
437 perror("socket_send");
442 mk_api
->socket_send(socket
, MK_CRLF
, 2);
443 mk_api
->socket_cork_flag(socket
, TCP_CORK_OFF
);
447 int mk_palm_send_end_chunk(int socket
)
451 n
= mk_api
->socket_send(socket
, "0\r\n\r\n", 5);
455 int _mkp_event_read(int sockfd
)
459 int headers_end
= -1;
461 struct mk_palm_request
*pr
;
463 pr
= mk_palm_request_get(sockfd
);
467 PLUGIN_TRACE("Invalid palm request, not found");
472 /* Reset read buffer */
473 bzero(pr
->data_read
, MK_PALM_BUFFER_SIZE
);
476 pr
->len_read
= mk_api
->socket_read(pr
->palm_fd
,
478 (MK_PALM_BUFFER_SIZE
- 1));
481 PLUGIN_TRACE("FD %i", sockfd
);
482 PLUGIN_TRACE(" socket read : %i", pr
->len_read
);
483 PLUGIN_TRACE(" headers sent : %i", pr
->headers_sent
);
486 if (pr
->len_read
<= 0) {
488 PLUGIN_TRACE("Ending connection: read() = %i", pr
->len_read
);
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
,
500 if (headers_end
== -1) {
501 headers_end
= mk_api
->str_search(pr
->data_read
,
505 /* Look for headers end */
506 while (headers_end
== -1) {
508 PLUGIN_TRACE("CANNOT FIND HEADERS_END in FD %i", pr
->palm_fd
);
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
);
519 PLUGIN_TRACE("[FD %i] N READ: %i", pr
->palm_fd
, n
);
520 PLUGIN_TRACE("********* FIXME ***********\n%s", pr
->data_read
);
525 headers_end
= (int) mk_api
->str_search(pr
->data_read
,
529 if (headers_end
> 0) {
534 PLUGIN_TRACE("SOMETHING BAD HAPPENS");
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
);
542 PLUGIN_TRACE("Headers sent to HTTP client: %i", n
);
545 /* Enable headers flag */
546 pr
->headers_sent
= VAR_ON
;
547 read_offset
= headers_end
;
551 while (sent
!= (pr
->len_read
- read_offset
)) {
553 PLUGIN_TRACE("LOOP");
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
);
561 n
= mk_api
->socket_send(pr
->client_fd
,
562 pr
->data_read
+ read_offset
+ sent
,
563 pr
->len_read
- read_offset
- sent
);
568 PLUGIN_TRACE("WRITE ERROR");
570 perror("socket_send");
571 return MK_PLUGIN_RET_END
;
575 PLUGIN_TRACE("BYTES SENT: %i", 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
);
588 PLUGIN_TRACE("FIXME!, this should not happend");
592 /* Update thread node info */
593 mk_palm_request_update(sockfd
, pr
);
598 /* sockfd = palm_fd */
599 int hangup(int sockfd
)
601 struct mk_palm_request
*pr
;
604 PLUGIN_TRACE("[FD %i] hangup", sockfd
);
607 pr
= mk_palm_request_get(sockfd
) ;
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
)
623 PLUGIN_TRACE("[FD %i] event close", sockfd
);
626 return hangup(sockfd
);
629 int _mkp_event_error(int sockfd
)
632 PLUGIN_TRACE("[FD %i] event error", sockfd
);
635 return hangup(sockfd
);