Change Monkey HTTP signature
[MonkeyD.git] / src / header.c
blobad5c253daf8ab920dbfe669796241c8e9b2d965c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /* Monkey HTTP Daemon
4 * ------------------
5 * Copyright (C) 2008, 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., 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"
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 pthread_getspecific(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, struct log_info *s_log)
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 s_log->status = S_LOG_OFF;
84 mk_header_iov_add_entry(iov, mk_hr_redir_moved,
85 mk_iov_none, MK_IOV_NOT_FREE_BUF);
86 break;
88 case M_REDIR_MOVED_T:
89 s_log->status = S_LOG_ON;
90 mk_header_iov_add_entry(iov, mk_hr_redir_moved_t,
91 mk_iov_none, MK_IOV_NOT_FREE_BUF);
92 break;
94 case M_NOT_MODIFIED:
95 s_log->status = S_LOG_OFF;
96 mk_header_iov_add_entry(iov, mk_hr_not_modified,
97 mk_iov_none, MK_IOV_NOT_FREE_BUF);
98 break;
100 case M_CLIENT_BAD_REQUEST:
101 mk_header_iov_add_entry(iov, mk_hr_client_bad_request,
102 mk_iov_none, MK_IOV_NOT_FREE_BUF);
103 break;
105 case M_CLIENT_FORBIDDEN:
106 mk_header_iov_add_entry(iov, mk_hr_client_forbidden,
107 mk_iov_none, MK_IOV_NOT_FREE_BUF);
108 break;
110 case M_CLIENT_NOT_FOUND:
111 mk_header_iov_add_entry(iov, mk_hr_client_not_found,
112 mk_iov_none, MK_IOV_NOT_FREE_BUF);
113 break;
115 case M_CLIENT_METHOD_NOT_ALLOWED:
116 mk_header_iov_add_entry(iov, mk_hr_client_method_not_allowed,
117 mk_iov_none, MK_IOV_NOT_FREE_BUF);
118 break;
120 case M_CLIENT_REQUEST_TIMEOUT:
121 mk_header_iov_add_entry(iov, mk_hr_client_request_timeout,
122 mk_iov_none, MK_IOV_NOT_FREE_BUF);
123 s_log->status = S_LOG_OFF;
124 break;
126 case M_CLIENT_LENGTH_REQUIRED:
127 mk_header_iov_add_entry(iov, mk_hr_client_length_required,
128 mk_iov_none, MK_IOV_NOT_FREE_BUF);
129 break;
131 case M_SERVER_NOT_IMPLEMENTED:
132 mk_header_iov_add_entry(iov, mk_hr_server_not_implemented,
133 mk_iov_none, MK_IOV_NOT_FREE_BUF);
134 break;
136 case M_SERVER_INTERNAL_ERROR:
137 mk_header_iov_add_entry(iov, mk_hr_server_internal_error,
138 mk_iov_none, MK_IOV_NOT_FREE_BUF);
139 break;
141 case M_SERVER_HTTP_VERSION_UNSUP:
142 mk_header_iov_add_entry(iov,
143 mk_hr_server_http_version_unsup,
144 mk_iov_none, MK_IOV_NOT_FREE_BUF);
145 break;
148 if (sh->status != 0) {
149 s_log->final_response = sh->status;
152 if (fd_status < 0) {
153 mk_header_iov_free(iov);
154 return -1;
157 /* Server details */
158 mk_iov_add_entry(iov, sr->host_conf->header_host_signature.data,
159 sr->host_conf->header_host_signature.len,
160 mk_iov_crlf, MK_IOV_NOT_FREE_BUF);
162 /* Date */
163 mk_iov_add_entry(iov,
164 mk_header_short_date.data,
165 mk_header_short_date.len,
166 mk_iov_header_value, MK_IOV_NOT_FREE_BUF);
167 mk_iov_add_entry(iov,
168 header_current_time.data,
169 header_current_time.len,
170 mk_iov_crlf, MK_IOV_NOT_FREE_BUF);
172 /* Connection */
173 if (config->keep_alive == VAR_ON &&
174 cr->request->connection.data != NULL &&
175 cr->request->keep_alive == VAR_ON &&
176 (cr->counter_connections < config->max_keep_alive_request)) {
177 m_build_buffer(&buffer,
178 &len,
179 "Keep-Alive: timeout=%i, max=%i"
180 MK_CRLF,
181 config->keep_alive_timeout,
182 (config->max_keep_alive_request -
183 cr->counter_connections)
185 mk_iov_add_entry(iov, buffer, len, mk_iov_none, MK_IOV_FREE_BUF);
186 mk_iov_add_entry(iov,
187 mk_header_conn_ka.data,
188 mk_header_conn_ka.len,
189 mk_iov_none, MK_IOV_NOT_FREE_BUF);
191 else if (sr->protocol >= HTTP_PROTOCOL_10 || sr->content_length == 0) {
192 mk_iov_add_entry(iov,
193 mk_header_conn_close.data,
194 mk_header_conn_close.len,
195 mk_iov_none, MK_IOV_NOT_FREE_BUF);
198 /* Location */
199 if (sh->location != NULL) {
200 mk_iov_add_entry(iov,
201 mk_header_short_location.data,
202 mk_header_short_location.len,
203 mk_iov_header_value, MK_IOV_NOT_FREE_BUF);
205 mk_iov_add_entry(iov,
206 sh->location,
207 strlen(sh->location), mk_iov_crlf, MK_IOV_FREE_BUF);
210 /* Last-Modified */
211 if (sh->last_modified.len > 0) {
212 mk_iov_add_entry(iov, mk_header_last_modified.data,
213 mk_header_last_modified.len,
214 mk_iov_header_value, MK_IOV_NOT_FREE_BUF);
215 mk_iov_add_entry(iov, sh->last_modified.data,
216 sh->last_modified.len,
217 mk_iov_crlf, MK_IOV_NOT_FREE_BUF);
220 /* Content type */
221 if (sh->content_type.len > 0) {
222 mk_iov_add_entry(iov,
223 mk_header_short_ct.data,
224 mk_header_short_ct.len,
225 mk_iov_header_value, MK_IOV_NOT_FREE_BUF);
227 mk_iov_add_entry(iov,
228 sh->content_type.data,
229 sh->content_type.len,
230 mk_iov_crlf, MK_IOV_NOT_FREE_BUF);
233 /* Transfer Encoding */
234 switch (sh->transfer_encoding) {
235 case MK_HEADER_TE_TYPE_CHUNKED:
236 mk_iov_add_entry(iov,
237 mk_header_te_chunked.data,
238 mk_header_te_chunked.len,
239 mk_iov_crlf, MK_IOV_NOT_FREE_BUF);
240 break;
243 /* Accept ranges
244 mk_iov_add_entry(iov,
245 mk_header_accept_ranges.data,
246 mk_header_accept_ranges.len,
247 mk_iov_crlf, MK_IOV_NOT_FREE_BUF);
249 /* TamaƱo total de la informacion a enviar */
250 if ((sh->content_length != 0 &&
251 (sh->ranges[0] >= 0 || sh->ranges[1] >= 0)) &&
252 config->resume == VAR_ON) {
253 long int length;
255 /* yyy- */
256 if (sh->ranges[0] >= 0 && sh->ranges[1] == -1) {
257 length = (unsigned int)
258 (sh->content_length - sh->ranges[0]);
259 m_build_buffer(&buffer, &len, "%s %i", RH_CONTENT_LENGTH, length);
260 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
262 m_build_buffer(&buffer,
263 &len,
264 "%s bytes %d-%d/%d",
265 RH_CONTENT_RANGE,
266 sh->ranges[0],
267 (sh->content_length - 1), sh->content_length);
268 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
271 /* yyy-xxx */
272 if (sh->ranges[0] >= 0 && sh->ranges[1] >= 0) {
273 length = (unsigned int)
274 abs(sh->ranges[1] - sh->ranges[0]) + 1;
275 m_build_buffer(&buffer, &len, "%s %d", RH_CONTENT_LENGTH, length);
276 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
278 m_build_buffer(&buffer,
279 &len,
280 "%s bytes %d-%d/%d",
281 RH_CONTENT_RANGE,
282 sh->ranges[0], sh->ranges[1], sh->content_length);
284 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
287 /* -xxx */
288 if (sh->ranges[0] == -1 && sh->ranges[1] > 0) {
289 length = (unsigned int) sh->ranges[1];
291 if (length > sh->content_length) {
292 length = sh->content_length;
293 sh->ranges[1] = sh->content_length;
296 m_build_buffer(&buffer, &len, "%s %d", RH_CONTENT_LENGTH, length);
297 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
299 m_build_buffer(&buffer,
300 &len,
301 "%s bytes %d-%d/%d",
302 RH_CONTENT_RANGE,
303 (sh->content_length - sh->ranges[1]),
304 (sh->content_length - 1), sh->content_length);
305 mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF);
308 else if (sh->content_length >= 0) {
309 mk_iov_add_entry(iov, mk_rh_content_length.data,
310 mk_rh_content_length.len,
311 mk_iov_space, MK_IOV_NOT_FREE_BUF);
313 mk_iov_add_entry(iov, sh->content_length_p.data,
314 sh->content_length_p.len,
315 mk_iov_crlf, MK_IOV_NOT_FREE_BUF);
318 if (sh->cgi == SH_NOCGI || sh->breakline == MK_HEADER_BREAKLINE) {
319 mk_iov_add_entry(iov, mk_iov_crlf.data, mk_iov_crlf.len,
320 mk_iov_none, MK_IOV_NOT_FREE_BUF);
323 mk_socket_set_cork_flag(fd, TCP_CORK_ON);
324 mk_iov_send(fd, iov, MK_IOV_SEND_TO_SOCKET);
326 #ifdef DEBUG_HEADERS_OUT
327 mk_iov_send(0, iov, MK_IOV_SEND_TO_SOCKET);
328 #endif
330 mk_header_iov_free(iov);
332 return 0;
335 char *mk_header_chunked_line(int len)
337 char *buf;
339 buf = mk_mem_malloc_z(10);
340 snprintf(buf, 9, "%x%s", len, MK_CRLF);
342 return buf;
345 struct header_values *mk_header_create()
347 struct header_values *headers;
349 headers =
350 (struct header_values *) mk_mem_malloc(sizeof(struct header_values));
351 headers->ranges[0] = -1;
352 headers->ranges[1] = -1;
353 headers->content_length = -1;
354 headers->transfer_encoding = -1;
355 mk_pointer_reset(&headers->content_length_p);
356 mk_pointer_reset(&headers->content_type);
357 mk_pointer_reset(&headers->last_modified);
358 headers->location = NULL;
360 return headers;