root/trunk/src/connections.c

Revision 2263, 40.1 kB (checked in by stbuehler, 3 weeks ago)

Replace buffer_{append,copy}_string with the _len variant where possible (#1732, thx crypt)
Replace BUFFER_{APPEND,COPY}_STRING_CONST with _len(b, CONST_STRL_LEN(x))

  • Property svn:eol-style set to native
Line 
1#include <sys/stat.h>
2
3#include <stdlib.h>
4#include <stdio.h>
5#include <errno.h>
6#include <string.h>
7#include <fcntl.h>
8#include <assert.h>
9
10#include "settings.h"
11
12#include "server.h"
13#include "connections.h"
14#include "fdevent.h"
15#include "log.h"
16
17#include "request.h"
18#include "response.h"
19#include "network.h"
20#include "stat_cache.h"
21#include "joblist.h"
22
23#include "plugin.h"
24
25#include "inet_ntop_cache.h"
26#include "configfile.h"
27#include "http_req.h"
28
29#ifdef USE_OPENSSL
30# include <openssl/ssl.h>
31# include <openssl/err.h>
32#endif
33
34#ifdef HAVE_SYS_FILIO_H
35# include <sys/filio.h>
36#endif
37
38#include "sys-socket.h"
39#include "sys-files.h"
40
41typedef struct {
42        PLUGIN_DATA;
43} plugin_data;
44
45static connection *connections_get_new_connection(server *srv) {
46        connections *conns = srv->conns;
47        size_t i;
48
49        if (conns->size == 0) {
50                conns->size = 128;
51                conns->ptr = NULL;
52                conns->ptr = malloc(sizeof(*conns->ptr) * conns->size);
53                for (i = 0; i < conns->size; i++) {
54                        conns->ptr[i] = connection_init(srv);
55                }
56        } else if (conns->size == conns->used) {
57                conns->size += 128;
58                conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
59
60                for (i = conns->used; i < conns->size; i++) {
61                        conns->ptr[i] = connection_init(srv);
62                }
63        }
64
65        connection_reset(srv, conns->ptr[conns->used]);
66
67        conns->ptr[conns->used]->ndx = conns->used;
68        return conns->ptr[conns->used++];
69}
70
71static int connection_del(server *srv, connection *con) {
72        size_t i;
73        connections *conns = srv->conns;
74        connection *temp;
75
76        if (con == NULL) return -1;
77
78        if (-1 == con->ndx) return -1;
79
80        i = con->ndx;
81
82        /* not last element */
83
84        if (i != conns->used - 1) {
85                temp = conns->ptr[i];
86                conns->ptr[i] = conns->ptr[conns->used - 1];
87                conns->ptr[conns->used - 1] = temp;
88
89                conns->ptr[i]->ndx = i;
90                conns->ptr[conns->used - 1]->ndx = -1;
91        }
92
93        conns->used--;
94
95        con->ndx = -1;
96
97        return 0;
98}
99
100int connection_close(server *srv, connection *con) {
101#ifdef USE_OPENSSL
102        /* should be in iosocket_close() */
103
104        if (con->sock->ssl) {
105                int ret, ssl_r;
106                unsigned long err;
107
108                ERR_clear_error();
109                switch (ret = SSL_shutdown(con->sock->ssl)) {
110                case 1:
111                        /* done */
112                        break;
113                case 0:
114                        /* wait for fd-event
115                         *
116                         * FIXME: wait for fdevent and call SSL_shutdown again
117                         * (But it is not that important as we close the underlying connection anyway)
118                         */
119
120                        break;
121                default:
122                        switch ((ssl_r = SSL_get_error(con->sock->ssl, ret))) {
123                        case SSL_ERROR_WANT_WRITE:
124                        case SSL_ERROR_WANT_READ:
125                                break;
126                        case SSL_ERROR_SYSCALL:
127                                /* perhaps we have error waiting in our error-queue */
128                                if (0 != (err = ERR_get_error())) {
129                                        do {
130                                                ERROR("SSL_shutdown failed (%i, %i): %s", ssl_r, ret, ERR_error_string(err, NULL));
131                                        } while((err = ERR_get_error()));
132                                } else {
133                                        ERROR("SSL_shutdown failed (%i, %i, %i): %s", ssl_r, ret, errno, strerror(errno));
134                                }
135
136                                break;
137                        default:
138                                while((err = ERR_get_error())) {
139                                        ERROR("SSL_shutdown failed (%i, %i): %s", ssl_r, ret, ERR_error_string(err, NULL));
140                                }
141                        }
142                }
143
144                SSL_free(con->sock->ssl);
145                ERR_clear_error();
146                con->sock->ssl = NULL;
147        }
148#endif
149
150        fdevent_event_del(srv->ev, con->sock);
151        fdevent_unregister(srv->ev, con->sock);
152
153        if (closesocket(con->sock->fd)) {
154                log_error_write(srv, __FILE__, __LINE__, "sds",
155                                "(warning) close:", con->sock->fd, strerror(errno));
156        }
157
158        connection_del(srv, con);
159        connection_set_state(srv, con, CON_STATE_CONNECT);
160
161        return 0;
162}
163
164#if 0
165static void dump_packet(const unsigned char *data, size_t len) {
166        size_t i, j;
167
168        if (len == 0) return;
169
170        for (i = 0; i < len; i++) {
171                if (i % 16 == 0) fprintf(stderr, "  ");
172
173                fprintf(stderr, "%02x ", data[i]);
174
175                if ((i + 1) % 16 == 0) {
176                        fprintf(stderr, "  ");
177                        for (j = 0; j <= i % 16; j++) {
178                                unsigned char c;
179
180                                if (i-15+j >= len) break;
181
182                                c = data[i-15+j];
183
184                                fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
185                        }
186
187                        fprintf(stderr, "\n");
188                }
189        }
190
191        if (len % 16 != 0) {
192                for (j = i % 16; j < 16; j++) {
193                        fprintf(stderr, "   ");
194                }
195
196                fprintf(stderr, "  ");
197                for (j = i & ~0xf; j < len; j++) {
198                        unsigned char c;
199
200                        c = data[j];
201                        fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
202                }
203                fprintf(stderr, "\n");
204        }
205}
206#endif
207
208static int connection_handle_response_header(server *srv, connection *con) {
209        int no_response_body = 0;
210
211        if (con->mode == DIRECT) {
212                /* static files */
213                switch(con->request.http_method) {
214                case HTTP_METHOD_GET:
215                case HTTP_METHOD_POST:
216                case HTTP_METHOD_HEAD:
217                        /* webdav */
218                case HTTP_METHOD_PUT:
219                case HTTP_METHOD_MKCOL:
220                case HTTP_METHOD_DELETE:
221                case HTTP_METHOD_COPY:
222                case HTTP_METHOD_MOVE:
223                case HTTP_METHOD_PROPFIND:
224                case HTTP_METHOD_PROPPATCH:
225                case HTTP_METHOD_LOCK:
226                case HTTP_METHOD_UNLOCK:
227                        break;
228                case HTTP_METHOD_OPTIONS:
229                        /*
230                         * 400 is coming from the request-parser BEFORE uri.path is set
231                         * 403 is from the response handler when noone else catched it
232                         *
233                         * */
234                        if ((!con->http_status || con->http_status == 200) &&
235                            con->uri.path->used && con->uri.path->ptr[0] != '*') {
236                                response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
237
238                                /* trash the content */
239                                no_response_body = 1;
240
241                                con->http_status = 200;
242                        }
243                        break;
244                default:
245                        switch(con->http_status) {
246                        case 400: /* bad request */
247                        case 414: /* overload request header */
248                        case 505: /* unknown protocol */
249                        case 207: /* this was webdav */
250                                break;
251                        default:
252                                con->http_status = 501;
253                                break;
254                        }
255                        break;
256                }
257        }
258
259        if (con->http_status == 0) {
260                TRACE("%s", "no status, setting 403");
261                con->http_status = 403;
262        }
263
264        switch(con->http_status) {
265        case 400: /* class: header + custom body */
266        case 401:
267        case 403:
268        case 404:
269        case 408:
270        case 409:
271        case 410:
272        case 411:
273        case 416:
274        case 423:
275        case 500:
276        case 501:
277        case 502:
278        case 503:
279        case 504:
280        case 505:
281        case 509:
282                if (con->mode != DIRECT) break;
283
284                con->send->is_closed = 0;
285
286                buffer_reset(con->physical.path);
287
288                /* try to send static errorfile */
289                if (!buffer_is_empty(con->conf.errorfile_prefix)) {
290                        stat_cache_entry *sce = NULL;
291
292                        buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
293                        buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
294
295                        if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
296                                chunkqueue_append_file(con->send, con->physical.path, 0, sce->st.st_size);
297                                con->send->bytes_in += sce->st.st_size;
298                                con->send->is_closed = 1;
299                                response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
300                        }
301                }
302
303                if (!con->send->is_closed) {
304                        buffer *b;
305
306                        buffer_reset(con->physical.path);
307
308                        con->send->is_closed = 1;
309                        b = chunkqueue_get_append_buffer(con->send);
310
311                        /* build default error-page */
312                        buffer_copy_string_len(b, CONST_STR_LEN(
313                                           "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
314                                           "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
315                                           "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
316                                           "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
317                                           " <head>\n"
318                                           "  <title>"));
319                        buffer_append_long(b, con->http_status);
320                        buffer_append_string_len(b, CONST_STR_LEN(" - "));
321                        buffer_append_string(b, get_http_status_name(con->http_status));
322
323                        buffer_append_string(b,
324                                             "</title>\n"
325                                             " </head>\n"
326                                             " <body>\n"
327                                             "  <h1>");
328                        buffer_append_long(b, con->http_status);
329                        buffer_append_string_len(b, CONST_STR_LEN(" - "));
330                        buffer_append_string(b, get_http_status_name(con->http_status));
331
332                        buffer_append_string(b,"</h1>\n"
333                                             " </body>\n"
334                                             "</html>\n"
335                                             );
336
337                        con->send->bytes_in += b->used - 1;
338
339                        response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
340                }
341                /* fall through */
342        case 207:
343        case 200: /* class: header + body */
344        case 201:
345        case 301:
346        case 302:
347        case 303:
348                break;
349
350        case 206: /* write_queue is already prepared */
351                break;
352        case 205: /* class: header only */
353        case 304:
354        default:
355                if (con->mode == DIRECT) {
356                        /* only if we have handled the request internally
357                         * we will see no response-content
358                         *
359                         * if it was a fastcgi request we will see a END_REQUEST packet
360                         * after the header was parsed.
361                         *
362                         *  */
363                        no_response_body = 1;
364                }
365                break;
366        }
367
368        if (no_response_body) {
369                /* disable chunked encoding again as we have no body */
370                con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
371                chunkqueue_reset(con->send);
372
373                con->send->is_closed = 1;
374        }
375
376        return 0;
377}
378
379connection *connection_init(server *srv) {
380        connection *con;
381
382        UNUSED(srv);
383
384        con = calloc(1, sizeof(*con));
385
386        con->sock = iosocket_init();
387        con->ndx = -1;
388        con->bytes_written = 0;
389        con->bytes_read = 0;
390        con->bytes_header = 0;
391        con->loops_per_request = 0;
392
393#define CLEAN(x) \
394        con->x = buffer_init();
395
396        CLEAN(request.uri);
397        CLEAN(request.request);
398        CLEAN(request.pathinfo);
399        CLEAN(request.http_host);
400
401        CLEAN(request.orig_uri);
402
403        CLEAN(uri.scheme);
404        CLEAN(uri.authority);
405        CLEAN(uri.path);
406        CLEAN(uri.path_raw);
407        CLEAN(uri.query);
408
409        CLEAN(physical.doc_root);
410        CLEAN(physical.path);
411        CLEAN(physical.basedir);
412        CLEAN(physical.rel_path);
413        CLEAN(physical.etag);
414        CLEAN(parse_request);
415
416        CLEAN(authed_user);
417        CLEAN(server_name);
418        CLEAN(error_handler);
419        CLEAN(dst_addr_buf);
420
421#undef CLEAN
422        con->send_filters = filter_chain_init();
423        /* send is the chunkqueue of the first send filter */
424        con->send = con->send_filters->first->cq;
425        con->recv = chunkqueue_init();
426        chunkqueue_set_tempdirs(con->recv, srv->srvconf.upload_tempdirs);
427
428        con->send_raw = chunkqueue_init();
429        con->recv_raw = chunkqueue_init();
430
431        con->request.headers      = array_init();
432        con->response.headers     = array_init();
433        con->environment     = array_init();
434
435        con->http_req = http_request_init();
436
437        /* init plugin specific connection structures */
438
439        con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
440
441        con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
442        config_setup_connection(srv, con);
443
444        return con;
445}
446
447void connections_free(server *srv) {
448        connections *conns = srv->conns;
449        size_t i;
450
451        for (i = 0; i < conns->size; i++) {
452                connection *con = conns->ptr[i];
453
454                connection_reset(srv, con);
455                iosocket_free(con->sock);
456
457                filter_chain_free(con->send_filters);
458                con->send = NULL;
459                chunkqueue_free(con->recv);
460                chunkqueue_free(con->send_raw);
461                chunkqueue_free(con->recv_raw);
462                array_free(con->request.headers);
463                array_free(con->response.headers);
464                array_free(con->environment);
465
466#define CLEAN(x) \
467        buffer_free(con->x);
468
469                CLEAN(request.uri);
470                CLEAN(request.request);
471                CLEAN(request.pathinfo);
472                CLEAN(request.http_host);
473
474                CLEAN(request.orig_uri);
475
476                CLEAN(uri.scheme);
477                CLEAN(uri.authority);
478                CLEAN(uri.path);
479                CLEAN(uri.path_raw);
480                CLEAN(uri.query);
481
482                CLEAN(physical.doc_root);
483                CLEAN(physical.path);
484                CLEAN(physical.basedir);
485                CLEAN(physical.etag);
486                CLEAN(physical.rel_path);
487                CLEAN(parse_request);
488
489                CLEAN(authed_user);
490                CLEAN(server_name);
491                CLEAN(error_handler);
492                CLEAN(dst_addr_buf);
493#undef CLEAN
494                free(con->plugin_ctx);
495                free(con->cond_cache);
496
497                http_request_free(con->http_req);
498
499                free(con);
500        }
501
502        free(conns->ptr);
503}
504
505
506int connection_reset(server *srv, connection *con) {
507        size_t i;
508
509        plugins_call_connection_reset(srv, con);
510
511        con->is_readable = 1;
512        con->is_writable = 1;
513        con->http_status = 0;
514        con->file_started = 0;
515        con->got_response = 0;
516
517        con->bytes_written = 0;
518        con->bytes_written_cur_second = 0;
519        con->bytes_read = 0;
520        con->bytes_header = 0;
521        con->loops_per_request = 0;
522
523        con->request.http_method = HTTP_METHOD_UNSET;
524        con->request.http_version = HTTP_VERSION_UNSET;
525        con->request.content_length = -1;
526
527        con->response.keep_alive = 0;
528        con->response.content_length = -1;
529        con->response.transfer_encoding = 0;
530
531        con->mode = DIRECT;
532
533#define CLEAN(x) \
534        if (con->x) buffer_reset(con->x);
535
536        CLEAN(request.uri);
537        CLEAN(request.pathinfo);
538        CLEAN(request.request);
539        CLEAN(request.http_host);
540
541        CLEAN(request.orig_uri);
542
543        CLEAN(uri.scheme);
544        CLEAN(uri.authority);
545        CLEAN(uri.path);
546        CLEAN(uri.path_raw);
547        CLEAN(uri.query);
548
549        CLEAN(physical.doc_root);
550        CLEAN(physical.path);
551        CLEAN(physical.basedir);
552        CLEAN(physical.rel_path);
553        CLEAN(physical.etag);
554
555        CLEAN(parse_request);
556
557        CLEAN(authed_user);
558        CLEAN(server_name);
559        CLEAN(error_handler);
560#undef CLEAN
561
562#define CLEAN(x) \
563        if (con->x) con->x->used = 0;
564
565#undef CLEAN
566
567        array_reset(con->request.headers);
568        array_reset(con->response.headers);
569        array_reset(con->environment);
570
571        filter_chain_reset(con->send_filters);
572        con->send = con->send_filters->first->cq;
573        chunkqueue_reset(con->recv);
574        chunkqueue_reset(con->send_raw);
575
576        http_request_reset(con->http_req);
577
578        /* the plugins should cleanup themself */
579        for (i = 0; i < srv->plugins.used; i++) {
580                plugin *p = ((plugin **)(srv->plugins.ptr))[i];
581                plugin_data *pd = p->data;
582
583                if (!pd) continue;
584
585                if (con->plugin_ctx[pd->id] != NULL) {
586                        log_error_write(srv, __FILE__, __LINE__, "sb", "missing cleanup in", p->name);
587                }
588
589                con->plugin_ctx[pd->id] = NULL;
590        }
591
592        config_cond_cache_reset(srv, con);
593
594        con->header_len = 0;
595        con->in_error_handler = 0;
596
597        config_setup_connection(srv, con);
598
599        return 0;
600}
601
602/**
603 * handle all header and content read
604 *
605 * we get called by the state-engine and by the fdevent-handler
606 */
607handler_t connection_handle_read_request_header(server *srv, connection *con)  {
608        /* let's see if we need more data later */
609        fdevent_event_del(srv->ev, con->sock);
610
611        con->read_idle_ts = srv->cur_ts;  /* start a read-call() */
612
613        /* read from the network */
614        switch (network_read(srv, con, con->sock, con->recv_raw)) {
615        case NETWORK_STATUS_SUCCESS:
616                /* we read everything from the socket, do we have a full header ? */
617                break;
618        case NETWORK_STATUS_WAIT_FOR_EVENT:
619                fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
620                return HANDLER_WAIT_FOR_EVENT;
621        case NETWORK_STATUS_CONNECTION_CLOSE:
622                /* the connection went away before we got something back */
623                connection_set_state(srv, con, CON_STATE_CLOSE);
624
625                return HANDLER_GO_ON;
626        default:
627                ERROR("++ %s", "oops, something went wrong while reading");
628                return HANDLER_ERROR;
629        }
630
631        switch (http_request_parse_cq(con->recv_raw, con->http_req)) {
632        case PARSE_ERROR:
633                con->http_status = 400; /* the header is broken */
634                con->send->is_closed = 1; /* we have nothing to send */
635
636                chunkqueue_remove_finished_chunks(con->recv_raw);
637
638                return HANDLER_FINISHED;
639        case PARSE_NEED_MORE:
640                /* we need more */
641                fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
642
643                return HANDLER_WAIT_FOR_EVENT;
644        case PARSE_SUCCESS:
645                chunkqueue_remove_finished_chunks(con->recv_raw);
646                break;
647        default:
648                chunkqueue_remove_finished_chunks(con->recv_raw);
649                TRACE("%s", "(error)");
650                return HANDLER_ERROR;
651        }
652
653        return HANDLER_GO_ON;
654}
655
656/* decode the HTTP/1.1 chunk encoding */
657
658handler_t connection_handle_read_request_content(server *srv, connection *con)  {
659        /* read data from the socket and push it to the backend */
660
661        chunkqueue *in = con->recv_raw;
662        chunkqueue *out = con->recv; /* the pure content */
663        chunk *c;
664
665        /* let's see if we need more data later */
666        fdevent_event_del(srv->ev, con->sock);
667
668        con->read_idle_ts = srv->cur_ts;  /* start a read-call() */
669
670        if (con->request.content_length == -1) return HANDLER_GO_ON;
671
672        /* if the content was short enough, it might be read already */
673        if (in->first &&
674            chunkqueue_length(in) - in->first->offset > 0) {
675
676                /*
677                 * looks like the request-header also had some content for us
678                 */
679
680        } else {
681                /* read from the network */
682                switch (network_read(srv, con, con->sock, in)) {
683                case NETWORK_STATUS_SUCCESS:
684                        /* we have data */
685                        break;
686                case NETWORK_STATUS_WAIT_FOR_EVENT:
687                        fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
688                        return HANDLER_WAIT_FOR_EVENT;
689                case NETWORK_STATUS_CONNECTION_CLOSE:
690                        /* the connection went away before we got something back */
691                        connection_set_state(srv, con, CON_STATE_CLOSE);
692
693                        return HANDLER_GO_ON;
694                default:
695                        ERROR("++ %s", "oops, something went wrong while reading");
696                        return HANDLER_ERROR;
697                }
698        }
699
700        /* how much data do we want to extract ? */
701        for (c = in->first; c && (out->bytes_in != con->request.content_length); c = c->next) {
702                off_t weWant, weHave, toRead;
703
704                weWant = con->request.content_length - out->bytes_in;
705
706                if (c->mem->used == 0) continue;
707
708                weHave = c->mem->used - c->offset - 1;
709
710                toRead = weHave > weWant ? weWant : weHave;
711
712                /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
713                if (con->request.content_length > 64 * 1024) {
714                        chunk *dst_c = NULL;
715                        /* copy everything to max 1Mb sized tempfiles */
716
717                        /*
718                         * if the last chunk is
719                         * - smaller than 1Mb (size < 1Mb)
720                         * - not read yet (offset == 0)
721                         * -> append to it
722                         * otherwise
723                         * -> create a new chunk
724                         *
725                         * */
726
727                        if (out->last &&
728                            out->last->type == FILE_CHUNK &&
729                            out->last->file.is_temp &&
730                            out->last->offset == 0) {
731                                /* ok, take the last chunk for our job */
732
733                                if (out->last->file.length < 1 * 1024 * 1024) {
734                                        dst_c = out->last;
735
736                                        if (dst_c->file.fd == -1) {
737                                                /* this should not happen as we cache the fd, but you never know */
738                                                dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND);
739                                        }
740                                } else {
741                                        /* the chunk is too large now, close it */
742                                        dst_c = out->last;
743
744                                        if (dst_c->file.fd != -1) {
745                                                close(dst_c->file.fd);
746                                                dst_c->file.fd = -1;
747                                        }
748                                        dst_c = chunkqueue_get_append_tempfile(out);
749                                }
750                        } else {
751                                dst_c = chunkqueue_get_append_tempfile(out);
752                        }
753
754                        /* we have a chunk, let's write to it */
755
756                        if (dst_c->file.fd == -1) {
757                                /* we don't have file to write to,
758                                 * EACCES might be one reason.
759                                 *
760                                 * Instead of sending 500 we send 413 and say the request is too large
761                                 *  */
762
763                                log_error_write(srv, __FILE__, __LINE__, "sbs",
764                                                "denying upload as opening to temp-file for upload failed:",
765                                                dst_c->file.name, strerror(errno));
766
767                  Â