Load plugin trace message before load
[MonkeyD.git] / src / header.c
blob8aa1c5331fa0376e6daf64bd1cee0d3b72cef0c9
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. <edsiper@gmail.com>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
26 #include "monkey.h"
27 #include "header.h"
28 #include "memory.h"
29 #include "request.h"
30 #include "logfile.h"
31 #include "iov.h"
32 #include "http_status.h"
33 #include "config.h"
34 #include "socket.h"
35 #include "utils.h"
36 #include "clock.h"
37 #include "cache.h"
38 #include "http.h"
39 #include "str.h"
41 int mk_header_iov_add_entry(struct mk_iov *mk_io, mk_pointer data,
42 mk_pointer sep, int free)
44 return mk_iov_add_entry(mk_io, data.data, data.len, sep, free);
47 struct mk_iov *mk_header_iov_get()
49 return pthread_getspecific(mk_cache_iov_header);
52 void mk_header_iov_free(struct mk_iov *iov)
54 mk_iov_free_marked(iov);
57 /* Send_Header , envia las cabeceras principales */
58 int mk_header_send(int fd, struct client_request *cr,
59 struct request *sr, struct log_info *s_log)
61 int fd_status = 0;
62 unsigned long len = 0;
63 char *buffer = 0;
64 struct header_values *sh;
65 struct mk_iov *iov;
67 sh = sr->headers;
69 iov = mk_header_iov_get();
71 /* Status Code */
72 switch (sh->status) {
73 case M_HTTP_OK:
74 mk_header_iov_add_entry(iov, mk_hr_http_ok,
75 mk_iov_none, MK_IOV_NOT_FREE_BUF);
76 break;
78 case M_HTTP_PARTIAL:
79 mk_header_iov_add_entry(iov, mk_hr_http_partial,
80 mk_iov_none, MK_IOV_NOT_FREE_BUF);
81 break;
83 case M_REDIR_MOVED:
84 s_log->status = S_LOG_ON;
85 mk_header_iov_add_entry(iov, mk_hr_redir_moved,
86 mk_iov_none, MK_IOV_NOT_FREE_BUF);
87 break;
89 case M_REDIR_MOVED_T:
90 s_log->status = S_LOG_ON;
91 mk_header_iov_add_entry(iov, mk_hr_redir_moved_t,
92 mk_iov_none, MK_IOV_NOT_FREE_BUF);
93 break;
95 case M_NOT_MODIFIED:
96 s_log->status = S_LOG_ON;
97 mk_header_iov_add_entry(iov, mk_hr_not_modified,
98 mk_iov_none, MK_IOV_NOT_FREE_BUF);
99 break;
101 case M_CLIENT_BAD_REQUEST:
102 mk_header_iov_add_entry(iov, mk_hr_client_bad_request,
103 mk_iov_none, MK_IOV_NOT_FREE_BUF);
104 break;
106 case M_CLIENT_FORBIDDEN:
107 mk_header_iov_add_entry(iov, mk_hr_client_forbidden,
108 mk_iov_none, MK_IOV_NOT_FREE_BUF);
109 break;
111 case M_CLIENT_NOT_FOUND:
112 mk_header_iov_add_entry(iov, mk_hr_client_not_found,
113 mk_iov_none, MK_IOV_NOT_FREE_BUF);
114 break;
116 case M_CLIENT_METHOD_NOT_ALLOWED:
117 mk_header_iov_add_entry(iov, mk_hr_client_method_not_allowed,
118 mk_iov_none, MK_IOV_NOT_FREE_BUF);
119 break;
121 case M_CLIENT_REQUEST_TIMEOUT:
122 mk_header_iov_add_entry(iov, mk_hr_client_request_timeout,
123 mk_iov_none, MK_IOV_NOT_FREE_BUF);
124 s_log->status = S_LOG_OFF;
125 break;
127 case M_CLIENT_LENGTH_REQUIRED:
128 mk_header_iov_add_entry(iov, mk_hr_client_length_required,
129 mk_iov_none, MK_IOV_NOT_FREE_BUF);
130 break;
132 case M_SERVER_NOT_IMPLEMENTED:
133 mk_header_iov_add_entry(iov, mk_hr_server_not_implemented,
134 mk_iov_none, MK_IOV_NOT_FREE_BUF);
135 break;
137 case M_SERVER_INTERNAL_ERROR:
138 mk_header_iov_add_entry(iov, mk_hr_server_internal_error,
139 mk_iov_none, MK_IOV_NOT_FREE_BUF);
140 break;
142 case M_SERVER_HTTP_VERSION_UNSUP:
143 mk_header_iov_add_entry(iov,
144 mk_hr_server_http_version_unsup,
145 mk_iov_none, MK_IOV_NOT_FREE_BUF);
146 break;
149 if (sh->status != 0) {
150 s_log->final_response = sh->status;
153 if (fd_status < 0) {
154 mk_header_iov_free(iov);
155 return -1;
158 /* Server details */
159 mk_iov_add_entry(iov, sr->host_conf->header_host_signature.data,
160 sr->host_conf->header_host_signature.len,
161 mk_iov_crlf, MK_IOV_NOT_FREE_BUF);
163 /* Date */
164 mk_iov_add_entry(iov,
165 mk_header_short_date.data,
166 mk_header_short_date.len,
167 mk_iov_none, MK_IOV_NOT_FREE_BUF);
168 mk_iov_add_entry(iov,
169 header_current_time.data,
170 header_current_time.len,
171 mk_iov_none, MK_IOV_NOT_FREE_BUF);
173 /* Connection */
174 if (config->keep_alive == VAR_ON &&
175 sr->keep_alive == VAR_ON &&
176 cr->counter_connections < config->max_keep_alive_request) {
178 /* A valid connection header */
179 if (sr->connection.len > 0) {
180 mk_string_build(&buffer,
181 &len,
182 "Keep-Alive: timeout=%i, max=%i"
183 MK_CRLF,
184 config->keep_alive_timeout,
185 (config->max_keep_alive_request -
186 cr->counter_connections)
188 mk_iov_add_entry(iov, buffer, len, mk_iov_none, MK_IOV_FREE_BUF);
189 mk_iov_add_entry(iov,
190 mk_header_conn_ka.data,
191 mk_header_conn_ka.len,
192 mk_iov_none, MK_IOV_NOT_FREE_BUF);
195 else if(sr->close_now == VAR_ON) {
196 mk_iov_add_entry(iov,
197 mk_header_conn_close.data,
198 mk_header_conn_close.len,
199 mk_iov_none, MK_IOV_NOT_FREE_BUF);
202 /* Location */
203 if (sh->location != NULL) {
204 mk_iov_add_entry(iov,
205 mk_header_short_location.data,
206 mk_header_short_location.len,
207 mk_iov_none, MK_IOV_NOT_FREE_BUF);
209 mk_iov_add_entry(iov,
210 sh->location,
211 strlen(sh->location), mk_iov_crlf, MK_IOV_FREE_BUF);
214 /* Last-Modified */
215 if (sh->last_modified.len > 0) {
216 mk_iov_add_entry(iov, mk_header_last_modified.data,
217 mk_header_last_modified.len,
218 mk_iov_none, MK_IOV_NOT_FREE_BUF);
219 mk_iov_add_entry(iov, sh->last_modified.data,
220 sh->last_modified.len,
221 mk_iov_none, MK_IOV_NOT_FREE_BUF);
224 /* Content type */
225 if (sh->content_type.len > 0) {
226 mk_iov_add_entry(iov,
227 mk_header_short_ct.data,
228 mk_header_short_ct.len,
229 mk_iov_none, MK_IOV_NOT_FREE_BUF);
231 mk_iov_add_entry(iov,
232 sh->content_type.data,
233 sh->content_type.len,
234 mk_iov_none, MK_IOV_NOT_FREE_BUF);
237 /* Transfer Encoding */
238 switch (sh->transfer_encoding) {
239 case MK_HEADER_TE_TYPE_CHUNKED:
240 mk_iov_add_entry(iov,
241 mk_header_te_chunked.data,
242 mk_header_te_chunked.len,
243 mk_iov_none, MK_IOV_NOT_FREE_BUF);
244 break;
247 /* Content-Length */
248 if ((sh->content_length != 0 &&
249 (sh->ranges[0] >= 0 || sh->ranges[1] >= 0)) &&
250 config->resume == VAR_ON) {
251 long int length = -1;
253 /* yyy- */
254 if (sh->ranges[0] >= 0 && sh->ranges[1] == -1) {
255 length = (unsigned int)
256 (sh->content_length - sh->ranges[0]);
257 mk_string_build(&buffer, &len, "%s %i", RH_CONTENT_LENGTH, length);
258 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
260 mk_string_build(&buffer,
261 &len,
262 "%s bytes %d-%d/%d",
263 RH_CONTENT_RANGE,
264 sh->ranges[0],
265 (sh->content_length - 1), sh->content_length);
266 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
269 /* yyy-xxx */
270 if (sh->ranges[0] >= 0 && sh->ranges[1] >= 0) {
271 length = (unsigned int)
272 abs(sh->ranges[1] - sh->ranges[0]) + 1;
273 mk_string_build(&buffer, &len, "%s %d", RH_CONTENT_LENGTH, length);
274 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
276 mk_string_build(&buffer,
277 &len,
278 "%s bytes %d-%d/%d",
279 RH_CONTENT_RANGE,
280 sh->ranges[0], sh->ranges[1], sh->content_length);
282 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
285 /* -xxx */
286 if (sh->ranges[0] == -1 && sh->ranges[1] > 0) {
287 length = (unsigned int) sh->ranges[1];
289 if (length > sh->content_length) {
290 length = sh->content_length;
291 sh->ranges[1] = sh->content_length;
294 mk_string_build(&buffer, &len, "%s %d", RH_CONTENT_LENGTH, length);
295 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
297 mk_string_build(&buffer,
298 &len,
299 "%s bytes %d-%d/%d",
300 RH_CONTENT_RANGE,
301 (sh->content_length - sh->ranges[1]),
302 (sh->content_length - 1), sh->content_length);
303 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
306 /* FIXME: logger routines and data should be handled by a plugin
307 * in Monkey 0.11.0
309 if (length >= 0) {
310 sr->log->size = length;
311 sr->log->size_p = mk_utils_int2mkp(length);
314 else if (sh->content_length >= 0) {
315 /* Map content length to MK_POINTER */
316 sh->content_length_p = mk_utils_int2mkp(sh->content_length);
318 /* Set headers */
319 mk_iov_add_entry(iov, mk_header_content_length.data,
320 mk_header_content_length.len,
321 mk_iov_none, MK_IOV_NOT_FREE_BUF);
322 mk_iov_add_entry(iov, sh->content_length_p.data, sh->content_length_p.len,
323 mk_iov_none, MK_IOV_FREE_BUF);
326 if (sh->cgi == SH_NOCGI || sh->breakline == MK_HEADER_BREAKLINE) {
327 mk_iov_add_entry(iov, mk_iov_crlf.data, mk_iov_crlf.len,
328 mk_iov_none, MK_IOV_NOT_FREE_BUF);
331 mk_socket_set_cork_flag(fd, TCP_CORK_ON);
332 mk_iov_send(fd, iov, MK_IOV_SEND_TO_SOCKET);
334 #ifdef TRACE
335 MK_TRACE("Headers sent");
336 printf("%s", ANSI_YELLOW);
337 fflush(stdout);
338 mk_iov_send(0, iov, MK_IOV_SEND_TO_SOCKET);
339 printf("%s", ANSI_RESET);
340 fflush(stdout);
341 #endif
343 mk_header_iov_free(iov);
344 return 0;
347 char *mk_header_chunked_line(int len)
349 char *buf;
351 buf = mk_mem_malloc_z(10);
352 snprintf(buf, 9, "%x%s", len, MK_CRLF);
354 return buf;
357 struct header_values *mk_header_create()
359 struct header_values *headers;
361 headers =
362 (struct header_values *) mk_mem_malloc(sizeof(struct header_values));
363 headers->ranges[0] = -1;
364 headers->ranges[1] = -1;
365 headers->content_length = -1;
366 headers->transfer_encoding = -1;
367 mk_pointer_reset(&headers->content_length_p);
368 mk_pointer_reset(&headers->content_type);
369 mk_pointer_reset(&headers->last_modified);
370 headers->location = NULL;
372 return headers;