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"
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.2";
46 mk_plugin_hook_t _hooks
= 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);
168 PLUGIN_TRACE( "Create environment for palm server");
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
);
180 if (sr
->method
== HTTP_METHOD_POST
&& sr
->content_length
> 0) {
181 /* FIX Content length:
182 mk_palm_iov_add_header(iov, mk_cgi_content_length,
185 mk_palm_iov_add_header(iov
, mk_cgi_content_type
, sr
->content_type
);
189 // mk_palm_iov_add_header(iov, mk_cgi_server_addr, mk_api->config->server_addr);
190 mk_palm_iov_add_header(iov
, mk_cgi_server_name
, sr
->host
);
191 mk_palm_iov_add_header(iov
, mk_cgi_server_protocol
, mk_monkey_protocol
);
192 mk_palm_iov_add_header(iov
, mk_cgi_server_software
,
193 mk_api
->config
->server_software
);
194 //mk_palm_iov_add_header(iov, mk_cgi_server_signature, sr->host_conf->host_signature);
196 if (sr
->user_agent
.data
)
197 mk_palm_iov_add_header(iov
, mk_cgi_http_user_agent
, sr
->user_agent
);
200 mk_palm_iov_add_header(iov
, mk_cgi_http_accept
, sr
->accept
);
202 if (sr
->accept_charset
.data
)
203 mk_palm_iov_add_header(iov
, mk_cgi_http_accept_charset
,
206 if (sr
->accept_encoding
.data
)
207 mk_palm_iov_add_header(iov
, mk_cgi_http_accept_encoding
,
208 sr
->accept_encoding
);
210 if (sr
->accept_language
.data
)
211 mk_palm_iov_add_header(iov
, mk_cgi_http_accept_language
,
212 sr
->accept_language
);
215 mk_palm_iov_add_header(iov
, mk_cgi_http_host
, sr
->host
);
217 if (sr
->cookies
.data
)
218 mk_palm_iov_add_header(iov
, mk_cgi_http_cookie
, sr
->cookies
);
220 if (sr
->referer
.data
)
221 mk_palm_iov_add_header(iov
, mk_cgi_http_referer
, sr
->referer
);
223 // mk_palm_iov_add_header(iov, mk_cgi_server_port, mk_monkey_port);
224 mk_palm_iov_add_header(iov
, mk_cgi_gateway_interface
, mk_cgi_version
);
225 //mk_palm_iov_add_header(iov, mk_cgi_remote_addr, cr->ip);
226 mk_palm_iov_add_header(iov
, mk_cgi_request_uri
, sr
->uri
);
227 //mk_palm_iov_add_header(iov, mk_cgi_request_method, sr->method);
228 mk_palm_iov_add_header(iov
, mk_cgi_script_name
, sr
->uri
);
231 /* real path is not an mk_pointer */
232 mk_palm_iov_add_header(iov
, mk_cgi_script_filename
, sr
->real_path
);
233 //mk_palm_iov_add_header(iov, mk_cgi_remote_port, cr->port);
234 mk_palm_iov_add_header(iov
, mk_cgi_query_string
, sr
->query_string
);
235 //mk_palm_iov_add_header(iov, mk_cgi_post_vars, sr->post_variables);
238 mk_api
->iov_add_entry(iov
, mk_iov_crlf
.data
, mk_iov_crlf
.len
,
239 mk_iov_none
, MK_IOV_NOT_FREE_BUF
);
240 mk_api
->iov_add_entry(iov
, mk_iov_crlf
.data
, mk_iov_crlf
.len
,
241 mk_iov_none
, MK_IOV_NOT_FREE_BUF
);
242 mk_api
->iov_add_entry(iov
, mk_iov_crlf
.data
, mk_iov_crlf
.len
,
243 mk_iov_none
, MK_IOV_NOT_FREE_BUF
);
248 int mk_palm_send_headers(struct client_request
*cr
, struct request
*sr
)
252 sr
->headers
->status
= M_HTTP_OK
;
253 sr
->headers
->cgi
= SH_CGI
;
255 /* Chunked transfer encoding */
256 if (sr
->protocol
>= HTTP_PROTOCOL_11
) {
257 sr
->headers
->transfer_encoding
= MK_HEADER_TE_TYPE_CHUNKED
;
260 /* Send just headers from buffer */
261 PLUGIN_TRACE("Sending headers to FD %i", cr
->socket
);
263 n
= (int) mk_api
->header_send(cr
->socket
, cr
, sr
, sr
->log
);
265 /* Monkey core send_headers set TCP_CORK_ON, we need to get
266 * back the status to OFF
268 mk_api
->socket_cork_flag(cr
->socket
, TCP_CORK_OFF
);
269 PLUGIN_TRACE("Send headers returned %i", n
);
275 int _mkp_init(void **api
, char *confdir
)
280 /* Init some pointers */
281 mk_api
->pointer_set(&mk_monkey_protocol
, HTTP_PROTOCOL_11_STR
);
282 mk_api
->pointer_set(&mk_iov_crlf
, MK_IOV_CRLF
);
283 mk_api
->pointer_set(&mk_iov_equal
, MK_IOV_EQUAL
);
285 /* Read configuration */
286 mk_palm_conf(confdir
);
290 int _mkp_stage_10(struct server_config
*config
)
296 int _mkp_stage_40(struct plugin
*plugin
, struct client_request
*cr
, struct request
*sr
)
298 struct mk_palm
*palm
;
299 struct mk_palm_request
*pr
;
301 PLUGIN_TRACE("PALM STAGE 40, requesting '%s'", sr
->real_path
.data
);
303 palm
= mk_palm_get_handler(&sr
->uri
);
305 PLUGIN_TRACE("PALM NOT ME");
306 return MK_PLUGIN_RET_NOT_ME
;
309 /* Connect to server */
310 pr
= mk_palm_do_instance(palm
, cr
, sr
);
313 PLUGIN_TRACE("return %i (MK_PLUGIN_RET_END)", MK_PLUGIN_RET_END
);
314 return MK_PLUGIN_RET_END
;
317 /* Register Palm instance */
318 mk_palm_request_add(pr
);
320 /* Register socket with thread Epoll interface */
321 mk_api
->event_add(pr
->palm_fd
, MK_EPOLL_READ
, plugin
, cr
, sr
);
322 PLUGIN_TRACE("Palm: Event registered for palm_socket=%i", pr
->palm_fd
);
325 mk_palm_send_headers(cr
, sr
);
326 mk_palm_send_request(cr
, sr
);
328 PLUGIN_TRACE("return %i (MK_PLUGIN_RET_CONTINUE)", MK_PLUGIN_RET_CONTINUE
);
330 return MK_PLUGIN_RET_CONTINUE
;
335 struct mk_palm_request
*mk_palm_do_instance(struct mk_palm
*palm
,
336 struct client_request
*cr
,
342 /* Get Palm handler */
343 // palm = mk_palm_get_handler(&sr->uri);
345 /* Connecting to Palm Server */
346 palm_socket
= mk_api
->socket_create();
347 ret
= mk_api
->socket_connect(palm_socket
,
352 fprintf(stderr
, "\nPalm: Cannot connect to %s on port %i",
353 palm
->server_addr
, palm
->server_port
);
357 /* Return instance */
358 return mk_palm_request_create(cr
->socket
, palm_socket
, cr
, sr
, palm
);
361 void mk_palm_send_request(struct client_request
*cr
, struct request
*sr
)
364 ssize_t bytes_iov
=-1;
366 struct mk_palm_request
*pr
;
368 PLUGIN_TRACE("Sending request to Palm Server");
370 pr
= mk_palm_request_get(cr
->socket
);
372 if (pr
->bytes_sent
== 0) {
374 PLUGIN_TRACE("Palm request: '%s'", sr
->real_path
.data
);
376 /* Palm environment vars */
377 iov
= mk_palm_create_env(cr
, sr
);
379 /* Write request to palm server */
380 bytes_iov
= (ssize_t
)mk_api
->iov_send(pr
->palm_fd
, iov
, MK_IOV_SEND_TO_SOCKET
);
383 pr
->bytes_sent
+= bytes_iov
;
384 n
= (long) bytes_iov
;
388 mk_api
->socket_set_tcp_nodelay(pr
->palm_fd
);
389 mk_api
->socket_set_nonblocking(pr
->palm_fd
);
393 PLUGIN_TRACE("Bytes sent to PALM SERVER: %i", pr
->bytes_sent
);
396 int mk_palm_send_chunk(int socket
, void *buffer
, unsigned int len
)
400 unsigned long chunk_len
=0;
403 mk_api
->socket_cork_flag(socket
, TCP_CORK_ON
);
404 mk_api
->str_build(&chunk_size
, &chunk_len
, "%x%s", len
, MK_CRLF
);
405 n
= mk_api
->socket_send(socket
, chunk_size
, chunk_len
);
406 mk_api
->mem_free(chunk_size
);
409 PLUGIN_TRACE("Error sending chunked header, socket_send() returned %i", n
);
410 perror("socket_send");
414 n
= mk_api
->socket_send(socket
, buffer
, len
);
415 PLUGIN_TRACE("SEND CHUNK: requested %i, sent %i", len
, n
);
418 PLUGIN_TRACE("Error sending chunked body, socket_send() returned %i", n
);
419 perror("socket_send");
423 mk_api
->socket_send(socket
, MK_CRLF
, 2);
424 mk_api
->socket_cork_flag(socket
, TCP_CORK_OFF
);
428 int _mkp_event_read(struct client_request
*cr
, struct request
*sr
)
432 int headers_end
= -1;
434 struct mk_palm_request
*pr
;
436 pr
= mk_palm_request_get(cr
->socket
);
439 PLUGIN_TRACE("Invalid palm request, not found");
443 /* Reset read buffer */
444 bzero(pr
->data_read
, MK_PALM_BUFFER_SIZE
);
447 pr
->len_read
= mk_api
->socket_read(pr
->palm_fd
,
449 (MK_PALM_BUFFER_SIZE
- 1));
451 if (pr
->len_read
<= 0) {
452 PLUGIN_TRACE("Ending connection: read() = %i", pr
->len_read
);
453 return MK_PLUGIN_RET_END
;
455 else if (pr
->len_read
> 0) {
456 if (pr
->headers_sent
== VAR_OFF
) {
457 headers_end
= (int) mk_api
->str_search(pr
->data_read
,
459 /* Look for headers end */
460 while (headers_end
== -1) {
461 PLUGIN_TRACE("CANNOT FIND HEADERS_END :/");
463 n
= mk_api
->socket_read(pr
->palm_fd
,
464 pr
->data_read
+ pr
->len_read
,
465 (MK_PALM_BUFFER_SIZE
-1) - pr
->len_read
);
471 PLUGIN_TRACE("********* FIXME ***********");
474 headers_end
= (int) mk_api
->str_search(pr
->data_read
,
478 if (headers_end
> 0) {
482 PLUGIN_TRACE("SOMETHING BAD HAPPENS");
485 /* FIXME: What about if this socket_send wrote partial headers ? ugh! */
486 n
= mk_api
->socket_send(cr
->socket
, pr
->data_read
, headers_end
);
488 PLUGIN_TRACE("Headers sent to HTTP client: %i", n
);
490 /* Enable headers flag */
491 pr
->headers_sent
= VAR_ON
;
492 read_offset
= headers_end
;
496 while (sent
!= (pr
->len_read
- read_offset
)) {
497 PLUGIN_TRACE("LOOP");
498 n
= mk_palm_send_chunk(cr
->socket
,
499 pr
->data_read
+ read_offset
+ sent
,
500 pr
->len_read
- read_offset
- sent
);
503 PLUGIN_TRACE("WRITE ERROR");
504 perror("socket_send");
505 return MK_PLUGIN_RET_END
;
508 PLUGIN_TRACE("BYTES SENT: %i", n
);
514 mk_api
->socket_cork_flag(cr
->socket
, TCP_CORK_OFF
);
515 ret
= MK_PLUGIN_RET_CONTINUE
;
517 mk_palm_request_update(cr
->socket
, pr
);
520 PLUGIN_TRACE("BIG ERROR!");
523 /* Update thread node info */
524 mk_palm_request_update(cr
->socket
, pr
);
529 void _mkp_event_close(struct client_request
*cr
, struct request
*sr
)
531 PLUGIN_TRACE("Closing socket to Palm server");
532 mk_api
->socket_close(cr
->socket
);
535 void _mkp_event_error(struct client_request
*cr
, struct request
*sr
)
537 PLUGIN_TRACE( " ERROR ERROR " );
538 mk_api
->socket_close(cr
->socket
);