~ubuntu-branches/ubuntu/natty/lighttpd/natty

« back to all changes in this revision

Viewing changes to src/http-header-glue.c

  • Committer: Bazaar Package Importer
  • Author(s): Torsten Marek
  • Date: 2005-11-26 11:48:51 UTC
  • Revision ID: james.westby@ubuntu.com-20051126114851-76t9q0rrwbzjnt2t
Tags: upstream-1.4.8
ImportĀ upstreamĀ versionĀ 1.4.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define _GNU_SOURCE
 
2
 
 
3
#include <string.h>
 
4
#include <errno.h>
 
5
#include <time.h>
 
6
 
 
7
#include "base.h"
 
8
#include "array.h"
 
9
#include "buffer.h"
 
10
#include "log.h"
 
11
#include "etag.h"
 
12
 
 
13
/*
 
14
 * This was 'borrowed' from tcpdump.
 
15
 *
 
16
 *
 
17
 * This is fun.
 
18
 *
 
19
 * In older BSD systems, socket addresses were fixed-length, and
 
20
 * "sizeof (struct sockaddr)" gave the size of the structure.
 
21
 * All addresses fit within a "struct sockaddr".
 
22
 *
 
23
 * In newer BSD systems, the socket address is variable-length, and
 
24
 * there's an "sa_len" field giving the length of the structure;
 
25
 * this allows socket addresses to be longer than 2 bytes of family
 
26
 * and 14 bytes of data.
 
27
 *
 
28
 * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553
 
29
 * variant of the old BSD scheme (with "struct sockaddr_storage" rather
 
30
 * than "struct sockaddr"), and some use the new BSD scheme.
 
31
 *
 
32
 * Some versions of GNU libc use neither scheme, but has an "SA_LEN()"
 
33
 * macro that determines the size based on the address family.  Other
 
34
 * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553
 
35
 * but not in the final version).  On the latter systems, we explicitly
 
36
 * check the AF_ type to determine the length; we assume that on
 
37
 * all those systems we have "struct sockaddr_storage".
 
38
 */
 
39
 
 
40
#ifdef HAVE_IPV6
 
41
# ifndef SA_LEN
 
42
#  ifdef HAVE_SOCKADDR_SA_LEN
 
43
#   define SA_LEN(addr)   ((addr)->sa_len)
 
44
#  else /* HAVE_SOCKADDR_SA_LEN */
 
45
#   ifdef HAVE_STRUCT_SOCKADDR_STORAGE
 
46
static size_t get_sa_len(const struct sockaddr *addr) {
 
47
        switch (addr->sa_family) {
 
48
                
 
49
#    ifdef AF_INET
 
50
        case AF_INET:
 
51
                return (sizeof (struct sockaddr_in));
 
52
#    endif
 
53
                
 
54
#    ifdef AF_INET6
 
55
        case AF_INET6:
 
56
                return (sizeof (struct sockaddr_in6));
 
57
#    endif
 
58
                
 
59
        default:
 
60
                return (sizeof (struct sockaddr));
 
61
                
 
62
        }
 
63
}
 
64
#    define SA_LEN(addr)   (get_sa_len(addr))
 
65
#   else /* HAVE_SOCKADDR_STORAGE */
 
66
#    define SA_LEN(addr)   (sizeof (struct sockaddr))
 
67
#   endif /* HAVE_SOCKADDR_STORAGE */
 
68
#  endif /* HAVE_SOCKADDR_SA_LEN */
 
69
# endif /* SA_LEN */
 
70
#endif
 
71
 
 
72
 
 
73
 
 
74
 
 
75
int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
 
76
        data_string *ds;
 
77
        
 
78
        UNUSED(srv);
 
79
 
 
80
        if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
 
81
                ds = data_response_init();
 
82
        }
 
83
        buffer_copy_string_len(ds->key, key, keylen);
 
84
        buffer_copy_string_len(ds->value, value, vallen);
 
85
        
 
86
        array_insert_unique(con->response.headers, (data_unset *)ds);
 
87
        
 
88
        return 0;
 
89
}
 
90
 
 
91
int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
 
92
        data_string *ds;
 
93
        
 
94
        UNUSED(srv);
 
95
 
 
96
        /* if there already is a key by this name overwrite the value */
 
97
        if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
 
98
                buffer_copy_string(ds->value, value);
 
99
                
 
100
                return 0;
 
101
        }
 
102
        
 
103
        return response_header_insert(srv, con, key, keylen, value, vallen);
 
104
}
 
105
 
 
106
int http_response_redirect_to_directory(server *srv, connection *con) {
 
107
        buffer *o;
 
108
        
 
109
        o = buffer_init();
 
110
        
 
111
        if (con->conf.is_ssl) {
 
112
                buffer_copy_string(o, "https://");
 
113
        } else {
 
114
                buffer_copy_string(o, "http://");
 
115
        }
 
116
        if (con->uri.authority->used) {
 
117
                buffer_append_string_buffer(o, con->uri.authority);
 
118
        } else {
 
119
                /* get the name of the currently connected socket */
 
120
                struct hostent *he;
 
121
#ifdef HAVE_IPV6
 
122
                char hbuf[256];
 
123
#endif
 
124
                sock_addr our_addr;
 
125
                socklen_t our_addr_len;
 
126
                
 
127
                our_addr_len = sizeof(our_addr);
 
128
                
 
129
                if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
 
130
                        con->http_status = 500;
 
131
                        
 
132
                        log_error_write(srv, __FILE__, __LINE__, "ss",
 
133
                                        "can't get sockname", strerror(errno));
 
134
                        
 
135
                        buffer_free(o);
 
136
                        return 0;
 
137
                }
 
138
                
 
139
                
 
140
                /* Lookup name: secondly try to get hostname for bind address */
 
141
                switch(our_addr.plain.sa_family) {
 
142
#ifdef HAVE_IPV6
 
143
                case AF_INET6:
 
144
                        if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6), 
 
145
                                             SA_LEN((const struct sockaddr *)&our_addr.ipv6), 
 
146
                                             hbuf, sizeof(hbuf), NULL, 0, 0)) {
 
147
                                
 
148
                                char dst[INET6_ADDRSTRLEN];
 
149
                                
 
150
                                log_error_write(srv, __FILE__, __LINE__,
 
151
                                                "SSSS", "NOTICE: getnameinfo failed: ",
 
152
                                                strerror(errno), ", using ip-address instead");
 
153
                                
 
154
                                buffer_append_string(o, 
 
155
                                                     inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr, 
 
156
                                                               dst, sizeof(dst)));
 
157
                        } else {
 
158
                                buffer_append_string(o, hbuf);
 
159
                        }
 
160
                        break;
 
161
#endif
 
162
                case AF_INET:
 
163
                        if (NULL == (he = gethostbyaddr((char *)&our_addr.ipv4.sin_addr, sizeof(struct in_addr), AF_INET))) {
 
164
                                log_error_write(srv, __FILE__, __LINE__,
 
165
                                                "SdSS", "NOTICE: gethostbyaddr failed: ",
 
166
                                                h_errno, ", using ip-address instead");
 
167
                                
 
168
                                buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
 
169
                        } else {
 
170
                                buffer_append_string(o, he->h_name);
 
171
                        }
 
172
                        break;
 
173
                default:
 
174
                        log_error_write(srv, __FILE__, __LINE__,
 
175
                                        "S", "ERROR: unsupported address-type");
 
176
                        
 
177
                        buffer_free(o);
 
178
                        return -1;
 
179
                }
 
180
                
 
181
                if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) || 
 
182
                      (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
 
183
                        buffer_append_string(o, ":");
 
184
                        buffer_append_long(o, srv->srvconf.port);
 
185
                }
 
186
        }
 
187
        buffer_append_string_buffer(o, con->uri.path);
 
188
        buffer_append_string(o, "/");
 
189
        if (!buffer_is_empty(con->uri.query)) {
 
190
                buffer_append_string(o, "?");
 
191
                buffer_append_string_buffer(o, con->uri.query);
 
192
        }
 
193
        
 
194
        response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
 
195
        
 
196
        con->http_status = 301;
 
197
        
 
198
        buffer_free(o);
 
199
        
 
200
        return 0;
 
201
}
 
202
 
 
203
buffer * strftime_cache_get(server *srv, time_t last_mod) {
 
204
        struct tm *tm;
 
205
        size_t i;
 
206
                
 
207
        for (i = 0; i < FILE_CACHE_MAX; i++) {
 
208
                /* found cache-entry */
 
209
                if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
 
210
                                
 
211
                /* found empty slot */
 
212
                if (srv->mtime_cache[i].mtime == 0) break;
 
213
        }
 
214
        
 
215
        if (i == FILE_CACHE_MAX) {
 
216
                i = 0;
 
217
        }
 
218
                
 
219
        srv->mtime_cache[i].mtime = last_mod;
 
220
        buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
 
221
        tm = gmtime(&(srv->mtime_cache[i].mtime));
 
222
        srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr, 
 
223
                                                 srv->mtime_cache[i].str->size - 1,
 
224
                                                 "%a, %d %b %Y %H:%M:%S GMT", tm);
 
225
        srv->mtime_cache[i].str->used++;
 
226
        
 
227
        return srv->mtime_cache[i].str;
 
228
}
 
229
 
 
230
 
 
231
int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
 
232
        /*
 
233
         * 14.26 If-None-Match
 
234
         *    [...]
 
235
         *    If none of the entity tags match, then the server MAY perform the
 
236
         *    requested method as if the If-None-Match header field did not exist,
 
237
         *    but MUST also ignore any If-Modified-Since header field(s) in the
 
238
         *    request. That is, if no entity tags match, then the server MUST NOT
 
239
         *    return a 304 (Not Modified) response.
 
240
         */
 
241
        
 
242
        /* last-modified handling */
 
243
        if (con->request.http_if_none_match) {
 
244
                if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
 
245
                        if (con->request.http_method == HTTP_METHOD_GET || 
 
246
                            con->request.http_method == HTTP_METHOD_HEAD) {
 
247
                                
 
248
                                /* check if etag + last-modified */
 
249
                                if (con->request.http_if_modified_since) {
 
250
                                        size_t used_len;
 
251
                                        char *semicolon;
 
252
                                        
 
253
                                        if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
 
254
                                                used_len = strlen(con->request.http_if_modified_since);
 
255
                                        } else {
 
256
                                                used_len = semicolon - con->request.http_if_modified_since;
 
257
                                        }
 
258
                                        
 
259
                                        if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
 
260
                                                con->http_status = 304;
 
261
                                                return HANDLER_FINISHED;
 
262
                                        } else {
 
263
                                                char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
 
264
 
 
265
                                                /* convert to timestamp */
 
266
                                                if (used_len < sizeof(buf)) {
 
267
                                                        time_t t_header, t_file;
 
268
                                                        struct tm tm;
 
269
                                                        
 
270
                                                        strncpy(buf, con->request.http_if_modified_since, used_len);
 
271
                                                        buf[used_len] = '\0';
 
272
                                                        
 
273
                                                        strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
 
274
                                                        t_header = mktime(&tm);
 
275
                                                        
 
276
                                                        strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
 
277
                                                        t_file = mktime(&tm);
 
278
 
 
279
                                                        if (t_file > t_header) {
 
280
                                                                con->http_status = 304;
 
281
                                                                return HANDLER_FINISHED;
 
282
                                                        }
 
283
                                                } else {
 
284
                                                        log_error_write(srv, __FILE__, __LINE__, "ssdd", 
 
285
                                                                        "DEBUG: Last-Modified check failed as the received timestamp was too long:", 
 
286
                                                                        con->request.http_if_modified_since, used_len, sizeof(buf) - 1);
 
287
                                                        
 
288
                                                        con->http_status = 412;
 
289
                                                        return HANDLER_FINISHED;
 
290
                                                }
 
291
                                        }
 
292
                                } else {
 
293
                                        con->http_status = 304;
 
294
                                        return HANDLER_FINISHED;
 
295
                                }
 
296
                        } else {
 
297
                                con->http_status = 412;
 
298
                                return HANDLER_FINISHED;
 
299
                        }
 
300
                }
 
301
        } else if (con->request.http_if_modified_since) {
 
302
                size_t used_len;
 
303
                char *semicolon;
 
304
                
 
305
                if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
 
306
                        used_len = strlen(con->request.http_if_modified_since);
 
307
                } else {
 
308
                        used_len = semicolon - con->request.http_if_modified_since;
 
309
                }
 
310
                
 
311
                if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
 
312
                        con->http_status = 304;
 
313
                        return HANDLER_FINISHED;
 
314
                }
 
315
        }
 
316
 
 
317
        return HANDLER_GO_ON;
 
318
}