Little Palm fixes
[MonkeyD.git] / src / header.c
blobd8fa8275a5481ba1aede34592aef989759b1561a
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 "iov.h"
31 #include "http_status.h"
32 #include "config.h"
33 #include "socket.h"
34 #include "utils.h"
35 #include "clock.h"
36 #include "cache.h"
37 #include "http.h"
38 #include "str.h"
40 int mk_header_iov_add_entry(struct mk_iov *mk_io, mk_pointer data,
41 mk_pointer sep, int free)
43 return mk_iov_add_entry(mk_io, data.data, data.len, sep, free);
46 struct mk_iov *mk_header_iov_get()
48 return mk_cache_get(mk_cache_iov_header);
51 void mk_header_iov_free(struct mk_iov *iov)
53 mk_iov_free_marked(iov);
56 /* Send_Header , envia las cabeceras principales */
57 int mk_header_send(int fd, struct client_request *cr,
58 struct request *sr)
60 int fd_status = 0;
61 unsigned long len = 0;
62 char *buffer = 0;
63 struct header_values *sh;
64 struct mk_iov *iov;
66 sh = sr->headers;
68 iov = mk_header_iov_get();
70 /* Status Code */
71 switch (sh->status) {
72 case M_HTTP_OK:
73 mk_header_iov_add_entry(iov, mk_hr_http_ok,
74 mk_iov_none, MK_IOV_NOT_FREE_BUF);
75 break;
77 case M_HTTP_PARTIAL:
78 mk_header_iov_add_entry(iov, mk_hr_http_partial,
79 mk_iov_none, MK_IOV_NOT_FREE_BUF);
80 break;
82 case M_REDIR_MOVED:
83 mk_header_iov_add_entry(iov, mk_hr_redir_moved,
84 mk_iov_none, MK_IOV_NOT_FREE_BUF);
85 break;
87 case M_REDIR_MOVED_T:
88 mk_header_iov_add_entry(iov, mk_hr_redir_moved_t,
89 mk_iov_none, MK_IOV_NOT_FREE_BUF);
90 break;
92 case M_NOT_MODIFIED:
93 mk_header_iov_add_entry(iov, mk_hr_not_modified,
94 mk_iov_none, MK_IOV_NOT_FREE_BUF);
95 break;
97 case M_CLIENT_BAD_REQUEST:
98 mk_header_iov_add_entry(iov, mk_hr_client_bad_request,
99 mk_iov_none, MK_IOV_NOT_FREE_BUF);
100 break;
102 case M_CLIENT_FORBIDDEN:
103 mk_header_iov_add_entry(iov, mk_hr_client_forbidden,
104 mk_iov_none, MK_IOV_NOT_FREE_BUF);
105 break;
107 case M_CLIENT_NOT_FOUND:
108 mk_header_iov_add_entry(iov, mk_hr_client_not_found,
109 mk_iov_none, MK_IOV_NOT_FREE_BUF);
110 break;
112 case M_CLIENT_METHOD_NOT_ALLOWED:
113 mk_header_iov_add_entry(iov, mk_hr_client_method_not_allowed,
114 mk_iov_none, MK_IOV_NOT_FREE_BUF);
115 break;
117 case M_CLIENT_REQUEST_TIMEOUT:
118 mk_header_iov_add_entry(iov, mk_hr_client_request_timeout,
119 mk_iov_none, MK_IOV_NOT_FREE_BUF);
120 break;
122 case M_CLIENT_LENGTH_REQUIRED:
123 mk_header_iov_add_entry(iov, mk_hr_client_length_required,
124 mk_iov_none, MK_IOV_NOT_FREE_BUF);
125 break;
127 case M_CLIENT_REQUEST_ENTITY_TOO_LARGE:
128 mk_header_iov_add_entry(iov, mk_hr_client_request_entity_too_large,
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;
147 default:
148 return -1;
151 if (fd_status < 0) {
152 mk_header_iov_free(iov);
153 return -1;
156 /* Server details */
157 mk_iov_add_entry(iov, sr->host_conf->header_host_signature.data,
158 sr->host_conf->header_host_signature.len,
159 mk_iov_crlf, MK_IOV_NOT_FREE_BUF);
161 /* Date */
162 mk_iov_add_entry(iov,
163 mk_header_short_date.data,
164 mk_header_short_date.len,
165 mk_iov_none, MK_IOV_NOT_FREE_BUF);
166 mk_iov_add_entry(iov,
167 header_current_time.data,
168 header_current_time.len,
169 mk_iov_none, MK_IOV_NOT_FREE_BUF);
171 /* Last-Modified */
172 if (sh->last_modified > 0) {
173 mk_pointer *lm;
174 lm = mk_cache_get(mk_cache_header_lm);
175 mk_utils_utime2gmt(&lm, sh->last_modified);
177 mk_iov_add_entry(iov, mk_header_last_modified.data,
178 mk_header_last_modified.len,
179 mk_iov_none, MK_IOV_NOT_FREE_BUF);
180 mk_iov_add_entry(iov, lm->data, lm->len,
181 mk_iov_none, MK_IOV_NOT_FREE_BUF);
184 /* Connection */
185 if (config->keep_alive == VAR_ON &&
186 sr->keep_alive == VAR_ON &&
187 cr->counter_connections < config->max_keep_alive_request) {
189 /* A valid connection header */
190 if (sr->connection.len > 0) {
191 mk_string_build(&buffer,
192 &len,
193 "Keep-Alive: timeout=%i, max=%i"
194 MK_CRLF,
195 config->keep_alive_timeout,
196 (config->max_keep_alive_request -
197 cr->counter_connections)
199 mk_iov_add_entry(iov, buffer, len, mk_iov_none, MK_IOV_FREE_BUF);
200 mk_iov_add_entry(iov,
201 mk_header_conn_ka.data,
202 mk_header_conn_ka.len,
203 mk_iov_none, MK_IOV_NOT_FREE_BUF);
206 else if(sr->close_now == VAR_ON) {
207 mk_iov_add_entry(iov,
208 mk_header_conn_close.data,
209 mk_header_conn_close.len,
210 mk_iov_none, MK_IOV_NOT_FREE_BUF);
213 /* Location */
214 if (sh->location != NULL) {
215 mk_iov_add_entry(iov,
216 mk_header_short_location.data,
217 mk_header_short_location.len,
218 mk_iov_none, MK_IOV_NOT_FREE_BUF);
220 mk_iov_add_entry(iov,
221 sh->location,
222 strlen(sh->location), mk_iov_crlf, MK_IOV_FREE_BUF);
225 /* Content type */
226 if (sh->content_type.len > 0) {
227 mk_iov_add_entry(iov,
228 mk_header_short_ct.data,
229 mk_header_short_ct.len,
230 mk_iov_none, MK_IOV_NOT_FREE_BUF);
232 mk_iov_add_entry(iov,
233 sh->content_type.data,
234 sh->content_type.len,
235 mk_iov_none, MK_IOV_NOT_FREE_BUF);
238 /* Transfer Encoding: the transfer encoding header is just sent when
239 * the response has some content defined by the HTTP status response
241 if ((sh->status < M_REDIR_MULTIPLE) || (sh->status > M_REDIR_USE_PROXY)) {
242 switch (sh->transfer_encoding) {
243 case MK_HEADER_TE_TYPE_CHUNKED:
244 mk_iov_add_entry(iov,
245 mk_header_te_chunked.data,
246 mk_header_te_chunked.len,
247 mk_iov_none, MK_IOV_NOT_FREE_BUF);
248 break;
252 /* Content-Length */
253 if (sh->content_length >= 0 && sr->method != HTTP_METHOD_HEAD) {
254 /* Map content length to MK_POINTER */
255 mk_pointer *cl;
256 cl = mk_cache_get(mk_cache_header_cl);
257 mk_string_itop(sh->content_length, cl);
259 /* Set headers */
260 mk_iov_add_entry(iov, mk_header_content_length.data,
261 mk_header_content_length.len,
262 mk_iov_none, MK_IOV_NOT_FREE_BUF);
264 mk_iov_add_entry(iov, cl->data, cl->len,
265 mk_iov_none, MK_IOV_NOT_FREE_BUF);
269 if ((sh->content_length != 0 &&
270 (sh->ranges[0] >= 0 || sh->ranges[1] >= 0)) &&
271 config->resume == VAR_ON) {
272 buffer = 0;
274 /* yyy- */
275 if (sh->ranges[0] >= 0 && sh->ranges[1] == -1) {
276 mk_string_build(&buffer,
277 &len,
278 "%s bytes %d-%d/%d",
279 RH_CONTENT_RANGE,
280 sh->ranges[0],
281 (sh->real_length - 1), sh->real_length);
282 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
285 /* yyy-xxx */
286 if (sh->ranges[0] >= 0 && sh->ranges[1] >= 0) {
287 mk_string_build(&buffer,
288 &len,
289 "%s bytes %d-%d/%d",
290 RH_CONTENT_RANGE,
291 sh->ranges[0], sh->ranges[1], sh->real_length);
293 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
296 /* -xxx */
297 if (sh->ranges[0] == -1 && sh->ranges[1] > 0) {
298 mk_string_build(&buffer,
299 &len,
300 "%s bytes %d-%d/%d",
301 RH_CONTENT_RANGE,
302 (sh->real_length - sh->ranges[1]),
303 (sh->real_length - 1), sh->real_length);
304 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
308 if (sh->cgi == SH_NOCGI || sh->breakline == MK_HEADER_BREAKLINE) {
309 mk_iov_add_entry(iov, mk_iov_crlf.data, mk_iov_crlf.len,
310 mk_iov_none, MK_IOV_NOT_FREE_BUF);
313 mk_socket_set_cork_flag(fd, TCP_CORK_ON);
314 mk_iov_send(fd, iov, MK_IOV_SEND_TO_SOCKET);
316 #ifdef TRACE
317 MK_TRACE("Headers sent to FD %i", fd);
318 printf("%s", ANSI_YELLOW);
319 fflush(stdout);
320 mk_iov_send(0, iov, MK_IOV_SEND_TO_SOCKET);
321 printf("%s", ANSI_RESET);
322 fflush(stdout);
323 #endif
325 mk_header_iov_free(iov);
326 return 0;
329 char *mk_header_chunked_line(int len)
331 char *buf;
333 buf = mk_mem_malloc_z(10);
334 snprintf(buf, 9, "%x%s", len, MK_CRLF);
336 return buf;
339 void mk_header_set_http_status(struct request *sr, int status)
341 sr->headers->status = status;
344 struct header_values *mk_header_create()
346 struct header_values *headers;
348 headers =
349 (struct header_values *) mk_mem_malloc(sizeof(struct header_values));
350 headers->status = 0;
351 headers->ranges[0] = -1;
352 headers->ranges[1] = -1;
353 headers->content_length = -1;
354 headers->transfer_encoding = -1;
355 headers->last_modified = -1;
356 mk_pointer_reset(&headers->content_type);
357 headers->location = NULL;
359 return headers;