root/branches/2.0/varnish-cache/bin/varnishd/cache_center.c @ 4325

Revision 4325, 25.2 KB (checked in by tfheen, 11 months ago)

Merge r4263: Reject garbled requests

If we cannot even make sense of the request, don't bother with
attempting a reply.

Fixes #561

  • Property svn:keywords set to Id
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2008 Linpro AS
4 * All rights reserved.
5 *
6 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Id$
30 *
31 * This file contains the central state machine for pushing requests.
32 *
33 * We cannot just use direct calls because it is possible to kick a
34 * request back to the lookup stage (usually after a rewrite).  The
35 * state engine also allows us to break the processing up into some
36 * logical chunks which improves readability a little bit.
37 *
38 * Since the states are rather nasty in detail, I have decided to embedd
39 * a dot(1) graph in the source code comments.  So to see the big picture,
40 * extract the DOT lines and run though dot(1), for instance with the
41 * command:
42 *      sed -n '/^DOT/s///p' cache_center.c | dot -Tps > /tmp/_.ps
43 */
44
45/*
46DOT digraph vcl_center {
47xDOT    page="8.2,11.5"
48DOT     size="7.2,10.5"
49DOT     margin="0.5"
50DOT     center="1"
51DOT acceptor [
52DOT     shape=hexagon
53DOT     label="Request received"
54DOT ]
55DOT ERROR [shape=plaintext]
56DOT RESTART [shape=plaintext]
57DOT acceptor -> start [style=bold,color=green,weight=4]
58 */
59
60#include "config.h"
61
62#include <stdio.h>
63#include <errno.h>
64#include <math.h>
65#include <poll.h>
66#include <stdlib.h>
67#include <string.h>
68#include <unistd.h>
69
70#ifndef HAVE_SRANDOMDEV
71#include "compat/srandomdev.h"
72#endif
73
74#include "shmlog.h"
75#include "vcl.h"
76#include "cli_priv.h"
77#include "cache.h"
78#include "hash_slinger.h"
79
80static unsigned xids;
81
82/*--------------------------------------------------------------------
83 * WAIT
84 * Wait until we have a full request in our htc.
85 */
86
87static int
88cnt_wait(struct sess *sp)
89{
90        int i;
91        struct pollfd pfd[1];
92
93        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
94        AZ(sp->vcl);
95        AZ(sp->obj);
96        assert(sp->xid == 0);
97
98        i = HTC_Complete(sp->htc);
99        while (i == 0) {
100                if (params->session_linger > 0) {
101                        pfd[0].fd = sp->fd;
102                        pfd[0].events = POLLIN;
103                        pfd[0].revents = 0;
104                        i = poll(pfd, 1, params->session_linger);
105                        if (i == 0) {
106                                WSL(sp->wrk, SLT_Debug, sp->fd, "herding");
107                                VSL_stats->sess_herd++;
108                                sp->wrk = NULL;
109                                vca_return_session(sp);
110                                return (1);
111                        }
112                }
113                i = HTC_Rx(sp->htc);
114        }
115        if (i == 1) {
116                sp->step = STP_START;
117        } else {
118                if (i == -2)
119                        vca_close_session(sp, "overflow");
120                else if (i == -1 && Tlen(sp->htc->rxbuf) == 0 &&
121                    (errno == 0 || errno == ECONNRESET))
122                        vca_close_session(sp, "EOF");
123                else 
124                        vca_close_session(sp, "error");
125                sp->step = STP_DONE;
126        }
127        return (0);
128}
129
130/*--------------------------------------------------------------------
131 * We have a refcounted object on the session, now deliver it.
132 *
133DOT subgraph xcluster_deliver {
134DOT     deliver [
135DOT             shape=ellipse
136DOT             label="Filter obj.->resp."
137DOT     ]
138DOT     vcl_deliver [
139DOT             shape=record
140DOT             label="vcl_deliver()|resp."
141DOT     ]
142DOT     deliver2 [
143DOT             shape=ellipse
144DOT             label="Send resp + body"
145DOT     ]
146DOT     deliver -> vcl_deliver [style=bold,color=green,weight=4]
147DOT     vcl_deliver -> deliver2 [style=bold,color=green,weight=4,label=deliver]
148DOT     vcl_deliver -> errdeliver [label="error"]
149DOT     errdeliver [label="ERROR",shape=plaintext]
150DOT     vcl_deliver -> rstdeliver [label="restart",color=purple]
151DOT     rstdeliver [label="RESTART",shape=plaintext]
152DOT }
153DOT deliver2 -> DONE [style=bold,color=green,weight=4]
154 *
155 * XXX: Ideally we should make the req. available in vcl_deliver() but for
156 * XXX: reasons of economy we don't, since that allows us to reuse the space
157 * XXX: in sp->req for the response.
158 *
159 * XXX: Rather than allocate two http's and workspaces for all sessions to
160 * XXX: address this deficiency, we could make the VCL compiler set a flag
161 * XXX: if req. is used in vcl_deliver().  When the flag is set we would
162 * XXX: take the memory overhead, for instance by borrowing a struct bereq
163 * XXX: or similar.
164 *
165 * XXX: For now, wait until somebody asks for it.
166 */
167
168static int
169cnt_deliver(struct sess *sp)
170{
171
172        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
173        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
174        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
175
176        AZ(sp->bereq);
177
178        sp->t_resp = TIM_real();
179        if (sp->obj->objhead != NULL) {
180                sp->obj->last_use = sp->t_resp; /* XXX: locking ? */
181                EXP_Touch(sp->obj, sp->t_resp);
182        }
183        RES_BuildHttp(sp);
184        VCL_deliver_method(sp);
185        switch (sp->handling) {
186        case VCL_RET_DELIVER:
187                break;
188        case VCL_RET_RESTART:
189                INCOMPL();
190                break;
191        default:
192                WRONG("Illegal action in vcl_deliver{}");
193        }
194
195        sp->director = NULL;
196        sp->restarts = 0;
197
198        RES_WriteObj(sp);
199        AZ(sp->wrk->wfd);
200        HSH_Deref(&sp->obj);
201        sp->step = STP_DONE;
202        return (0);
203}
204
205/*--------------------------------------------------------------------
206 * This is the final state, figure out if we should close or recycle
207 * the client connection
208 *
209DOT     DONE [
210DOT             shape=hexagon
211DOT             label="Request completed"
212DOT     ]
213 */
214
215static int
216cnt_done(struct sess *sp)
217{
218        double dh, dp, da;
219        int i;
220
221        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
222        CHECK_OBJ_ORNULL(sp->vcl, VCL_CONF_MAGIC);
223
224        AZ(sp->obj);
225        AZ(sp->vbe);
226        AZ(sp->bereq);
227        sp->director = NULL;
228        sp->restarts = 0;
229
230        if (sp->vcl != NULL && sp->esis == 0) {
231                if (sp->wrk->vcl != NULL)
232                        VCL_Rel(&sp->wrk->vcl);
233                sp->wrk->vcl = sp->vcl;
234                sp->vcl = NULL;
235        }
236
237        sp->t_end = TIM_real();
238        sp->wrk->lastused = sp->t_end;
239        if (sp->xid == 0) {
240                sp->t_req = sp->t_end;
241                sp->t_resp = sp->t_end;
242        }
243        dp = sp->t_resp - sp->t_req;
244        da = sp->t_end - sp->t_resp;
245        dh = sp->t_req - sp->t_open;
246        WSL(sp->wrk, SLT_ReqEnd, sp->id, "%u %.9f %.9f %.9f %.9f %.9f",
247            sp->xid, sp->t_req, sp->t_end, dh, dp, da);
248
249        sp->xid = 0;
250        sp->t_open = sp->t_end;
251        sp->t_resp = NAN;
252        WSL_Flush(sp->wrk, 0);
253
254        /* If we did an ESI include, don't mess up our state */
255        if (sp->esis > 0)
256                return (1);
257
258        sp->t_req = NAN;
259
260        if (sp->fd >= 0 && sp->doclose != NULL) {
261                /*
262                 * This is an orderly close of the connection; ditch linger
263                 * before we close, to get queued data transmitted.
264                 */
265                TCP_linger(sp->fd, 0);
266                vca_close_session(sp, sp->doclose);
267        }
268        if (sp->fd < 0) {
269                SES_Charge(sp);
270                VSL_stats->sess_closed++;
271                sp->wrk = NULL;
272                SES_Delete(sp);
273                return (1);
274        }
275
276        /* Reset the workspace to the session-watermark */
277        WS_Reset(sp->ws, sp->ws_ses);
278
279        i = HTC_Reinit(sp->htc);
280        if (i == 1) {
281                VSL_stats->sess_pipeline++;
282                sp->step = STP_START;
283                return (0);
284        }
285        if (Tlen(sp->htc->rxbuf)) {
286                VSL_stats->sess_readahead++;
287                sp->step = STP_WAIT;
288                return (0);
289        }
290        if (params->session_linger > 0) {
291                VSL_stats->sess_linger++;
292                sp->step = STP_WAIT;
293                return (0);
294        }
295        VSL_stats->sess_herd++;
296        SES_Charge(sp);
297        sp->wrk = NULL;
298        vca_return_session(sp);
299        return (1);
300}
301
302/*--------------------------------------------------------------------
303 * Emit an error
304 *
305DOT subgraph xcluster_error {
306DOT     vcl_error [
307DOT             shape=record
308DOT             label="vcl_error()|resp."
309DOT     ]
310DOT     ERROR -> vcl_error
311DOT     vcl_error-> deliver [label=deliver]
312DOT }
313 */
314
315static int
316cnt_error(struct sess *sp)
317{
318        struct worker *w;
319        struct http *h;
320        char date[40];
321
322        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
323        AZ(sp->bereq);
324
325        w = sp->wrk;
326        if (sp->obj == NULL) {
327                HSH_Prealloc(sp, 1);
328                sp->obj = sp->wrk->nobj;
329                sp->obj->xid = sp->xid;
330                sp->obj->entered = sp->t_req;
331                sp->wrk->nobj = NULL;
332        } else {
333                /* XXX: Null the headers ? */
334        }
335        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
336        h = sp->obj->http;
337
338        if (sp->err_code < 100 || sp->err_code > 999)
339                sp->err_code = 501;
340
341        http_PutProtocol(w, sp->fd, h, "HTTP/1.1");
342        http_PutStatus(w, sp->fd, h, sp->err_code);
343        TIM_format(TIM_real(), date);
344        http_PrintfHeader(w, sp->fd, h, "Date: %s", date);
345        http_PrintfHeader(w, sp->fd, h, "Server: Varnish");
346        http_PrintfHeader(w, sp->fd, h, "Retry-After: %d", params->err_ttl);
347
348        if (sp->err_reason != NULL)
349                http_PutResponse(w, sp->fd, h, sp->err_reason);
350        else
351                http_PutResponse(w, sp->fd, h,
352                    http_StatusMessage(sp->err_code));
353        VCL_error_method(sp);
354
355        if (sp->handling == VCL_RET_RESTART && sp->restarts <  params->max_restarts) {
356                HSH_Drop(sp);
357                sp->director = NULL;
358                sp->restarts++;
359                sp->step = STP_RECV;
360                return (0);
361        } else if (sp->handling == VCL_RET_RESTART)
362                sp->handling = VCL_RET_DELIVER;
363                 
364
365        /* We always close when we take this path */
366        sp->doclose = "error";
367        sp->wantbody = 1;
368
369        assert(sp->handling == VCL_RET_DELIVER);
370        sp->err_code = 0;
371        sp->err_reason = NULL;
372        sp->step = STP_DELIVER;
373        return (0);
374}
375
376/*--------------------------------------------------------------------
377 * We have fetched the headers from the backend, ask the VCL code what
378 * to do next, then head off in that direction.
379 *
380DOT subgraph xcluster_fetch {
381DOT     fetch [
382DOT             shape=ellipse
383DOT             label="fetch from backend\n(find obj.ttl)"
384DOT     ]
385DOT     vcl_fetch [
386DOT             shape=record
387DOT             label="vcl_fetch()|req.\nobj.\nbereq."
388DOT     ]
389DOT     fetch -> vcl_fetch [style=bold,color=blue,weight=2]
390DOT     fetch_pass [
391DOT             shape=ellipse
392DOT             label="obj.pass=true"
393DOT     ]
394DOT     vcl_fetch -> fetch_pass [label="pass",style=bold,color=red]
395DOT }
396DOT fetch_pass -> deliver [style=bold,color=red]
397DOT vcl_fetch -> deliver [label="deliver",style=bold,color=blue,weight=2]
398DOT vcl_fetch -> recv [label="restart"]
399DOT vcl_fetch -> rstfetch [label="restart",color=purple]
400DOT rstfetch [label="RESTART",shape=plaintext]
401DOT fetch -> errfetch
402DOT vcl_fetch -> errfetch [label="error"]
403DOT errfetch [label="ERROR",shape=plaintext]
404 */
405
406static int
407cnt_fetch(struct sess *sp)
408{
409        int i;
410
411        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
412        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
413
414        AN(sp->bereq);
415        AN(sp->director);
416        AZ(sp->vbe);
417        i = Fetch(sp);
418        AZ(sp->wrk->wfd);
419        AZ(sp->vbe);
420        AN(sp->director);
421
422        if (i) {
423                sp->err_code = 503;
424                sp->step = STP_ERROR;
425                VBE_free_bereq(&sp->bereq);
426                HSH_Drop(sp);
427                AZ(sp->obj);
428                return (0);
429        }
430
431        RFC2616_cache_policy(sp, sp->obj->http);        /* XXX -> VCL */
432
433        sp->err_code = http_GetStatus(sp->obj->http);
434        VCL_fetch_method(sp);
435
436        VBE_free_bereq(&sp->bereq);
437
438        switch (sp->handling) {
439        case VCL_RET_RESTART:
440                HSH_Drop(sp);
441                sp->director = NULL;
442                sp->restarts++;
443                sp->step = STP_RECV;
444                return (0);
445        case VCL_RET_PASS:
446                sp->obj->pass = 1;
447                if (sp->obj->ttl - sp->t_req < params->default_ttl)
448                        sp->obj->ttl = sp->t_req + params->default_ttl;
449                break;
450        case VCL_RET_DELIVER:
451                break;
452        case VCL_RET_ERROR:
453                sp->step = STP_ERROR;
454                HSH_Drop(sp);
455                return (0);
456        default:
457                WRONG("Illegal action in vcl_fetch{}");
458        }
459
460        sp->obj->cacheable = 1;
461        if (sp->obj->objhead != NULL) {
462                VRY_Create(sp);
463                EXP_Insert(sp->obj);
464                AN(sp->obj->ban);
465                HSH_Unbusy(sp);
466        }
467        sp->acct_req.fetch++;
468        sp->step = STP_DELIVER;
469        return (0);
470}
471
472/*--------------------------------------------------------------------
473 * The very first request
474 */
475static int
476cnt_first(struct sess *sp)
477{
478
479        /*
480         * XXX: If we don't have acceptfilters we are somewhat subject
481         * XXX: to DoS'ing here.  One remedy would be to set a shorter
482         * XXX: SO_RCVTIMEO and once we have received something here
483         * XXX: increase it to the normal value.
484         */
485
486        assert(sp->xid == 0);
487        assert(sp->restarts == 0);
488        VCA_Prep(sp);
489
490        /* Record the session watermark */
491        sp->ws_ses = WS_Snapshot(sp->ws);
492
493        /* Receive a HTTP protocol request */
494        HTC_Init(sp->htc, sp->ws, sp->fd);
495        sp->wrk->lastused = sp->t_open;
496        sp->acct_req.sess++;
497        SES_RefSrcAddr(sp);
498
499        sp->step = STP_WAIT;
500        return (0);
501}
502
503/*--------------------------------------------------------------------
504 * HIT
505 * We had a cache hit.  Ask VCL, then march off as instructed.
506 *
507DOT subgraph xcluster_hit {
508DOT     hit [
509DOT             shape=record
510DOT             label="vcl_hit()|req.\nobj."
511DOT     ]
512DOT }
513DOT hit -> err_hit [label="error"]
514DOT err_hit [label="ERROR",shape=plaintext]
515DOT hit -> rst_hit [label="restart",color=purple]
516DOT rst_hit [label="RESTART",shape=plaintext]
517DOT hit -> pass [label=pass,style=bold,color=red]
518DOT hit -> deliver [label="deliver",style=bold,color=green,weight=4]
519 */
520
521static int
522cnt_hit(struct sess *sp)
523{
524
525        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
526        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
527        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
528
529        assert(!sp->obj->pass);
530
531        VCL_hit_method(sp);
532
533        if (sp->handling == VCL_RET_DELIVER) {
534                /* Dispose of any body part of the request */
535                FetchReqBody(sp);
536                sp->step = STP_DELIVER;
537                return (0);
538        }
539
540        /* Drop our object, we won't need it */
541        HSH_Deref(&sp->obj);
542
543        switch(sp->handling) {
544        case VCL_RET_PASS:
545                sp->step = STP_PASS;
546                return (0);
547        case VCL_RET_ERROR:
548                sp->step = STP_ERROR;
549                return (0);
550        case VCL_RET_RESTART:
551                sp->director = NULL;
552                sp->restarts++;
553                sp->step = STP_RECV;
554                return (0);
555        default:
556                WRONG("Illegal action in vcl_hit{}");
557        }
558}
559
560/*--------------------------------------------------------------------
561 * LOOKUP
562 * Hash things together and look object up in hash-table.
563 *
564 * LOOKUP consists of two substates so that we can reenter if we
565 * encounter a busy object.
566 *
567DOT subgraph xcluster_lookup {
568DOT     hash [
569DOT             shape=record
570DOT             label="vcl_hash()|req."
571DOT     ]
572DOT     lookup [
573DOT             shape=diamond
574DOT             label="obj in cache ?\ncreate if not"
575DOT     ]
576DOT     lookup2 [
577DOT             shape=diamond
578DOT             label="obj.pass ?"
579DOT     ]
580DOT     hash -> lookup [label="hash",style=bold,color=green,weight=4]
581DOT     lookup -> lookup2 [label="yes",style=bold,color=green,weight=4]
582DOT }
583DOT lookup2 -> hit [label="no", style=bold,color=green,weight=4]
584DOT lookup2 -> pass [label="yes",style=bold,color=red]
585DOT lookup -> miss [label="no",style=bold,color=blue,weight=2]
586 */
587
588static int
589cnt_lookup(struct sess *sp)
590{
591        struct object *o;
592
593        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
594        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
595
596        if (sp->obj == NULL) {
597                HSH_Prepare(sp, sp->vcl->nhashcount);
598                VCL_hash_method(sp);
599                assert(sp->handling == VCL_RET_HASH);
600        }
601
602        o = HSH_Lookup(sp);
603
604        if (o == NULL) {
605                /*
606                 * We lost the session to a busy object, disembark the
607                 * worker thread.   The hash code to restart the session,
608                 * still in STP_LOOKUP, later when the busy object isn't.
609                 */
610                return (1);
611        }
612
613        sp->obj = o;
614
615        /* If we inserted a new object it's a miss */
616        if (sp->obj->busy) {
617                VSL_stats->cache_miss++;
618                sp->step = STP_MISS;
619                return (0);
620        }
621
622        if (sp->obj->pass) {
623                VSL_stats->cache_hitpass++;
624                WSP(sp, SLT_HitPass, "%u", sp->obj->xid);
625                HSH_Deref(&sp->obj);
626                sp->step = STP_PASS;
627                return (0);
628        }
629
630        VSL_stats->cache_hit++;
631        WSP(sp, SLT_Hit, "%u", sp->obj->xid);
632        sp->step = STP_HIT;
633        return (0);
634}
635
636/*--------------------------------------------------------------------
637 * We had a miss, ask VCL, proceed as instructed
638 *
639DOT subgraph xcluster_miss {
640DOT     miss [
641DOT             shape=ellipse
642DOT             label="filter req.->bereq."
643DOT     ]
644DOT     vcl_miss [
645DOT             shape=record
646DOT             label="vcl_miss()|req.\nbereq."
647DOT     ]
648DOT     miss -> vcl_miss [style=bold,color=blue,weight=2]
649DOT }
650DOT vcl_miss -> rst_miss [label="restart",color=purple]
651DOT rst_miss [label="RESTART",shape=plaintext]
652DOT vcl_miss -> err_miss [label="error"]
653DOT err_miss [label="ERROR",shape=plaintext]
654DOT vcl_miss -> fetch [label="fetch",style=bold,color=blue,weight=2]
655DOT vcl_miss -> pass [label="pass",style=bold,color=red]
656DOT
657 */
658
659static int
660cnt_miss(struct sess *sp)
661{
662
663        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
664        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
665        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
666
667        http_FilterHeader(sp, HTTPH_R_FETCH);
668        VCL_miss_method(sp);
669        AZ(sp->obj->cacheable);
670        switch(sp->handling) {
671        case VCL_RET_ERROR:
672                HSH_Drop(sp);
673                VBE_free_bereq(&sp->bereq);
674                sp->step = STP_ERROR;
675                return (0);
676        case VCL_RET_PASS:
677                HSH_Drop(sp);
678                VBE_free_bereq(&sp->bereq);
679                sp->step = STP_PASS;
680                return (0);
681        case VCL_RET_FETCH:
682                sp->step = STP_FETCH;
683                return (0);
684        case VCL_RET_RESTART:
685                VBE_free_bereq(&sp->bereq);
686                INCOMPL();
687        default:
688                WRONG("Illegal action in vcl_miss{}");
689        }
690}
691
692/*--------------------------------------------------------------------
693 * Start pass processing by getting headers from backend, then
694 * continue in passbody.
695 *
696DOT subgraph xcluster_pass {
697DOT     pass [
698DOT             shape=ellipse
699DOT             label="deref obj."
700DOT     ]
701DOT     pass2 [
702DOT             shape=ellipse
703DOT             label="filter req.->bereq."
704DOT     ]
705DOT     vcl_pass [
706DOT             shape=record
707DOT             label="vcl_pass()|req.\nbereq."
708DOT     ]
709DOT     pass_do [
710DOT             shape=ellipse
711DOT             label="create anon object\n"
712DOT     ]
713DOT     pass -> pass2 [style=bold, color=red]
714DOT     pass2 -> vcl_pass [style=bold, color=red]
715DOT     vcl_pass -> pass_do [label="pass"] [style=bold, color=red]
716DOT }
717DOT pass_do -> fetch [style=bold, color=red]
718DOT vcl_pass -> rst_pass [label="restart",color=purple]
719DOT rst_pass [label="RESTART",shape=plaintext]
720DOT vcl_pass -> err_pass [label="error"]
721DOT err_pass [label="ERROR",shape=plaintext]
722 */
723
724static int
725cnt_pass(struct sess *sp)
726{
727
728        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
729        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
730        AZ(sp->obj);
731
732        http_FilterHeader(sp, HTTPH_R_PASS);
733
734        VCL_pass_method(sp);
735        if (sp->handling == VCL_RET_ERROR) {
736                VBE_free_bereq(&sp->bereq);
737                sp->step = STP_ERROR;
738                return (0);
739        }
740        assert(sp->handling == VCL_RET_PASS);
741        sp->acct_req.pass++;
742        HSH_Prealloc(sp, 0);
743        sp->obj = sp->wrk->nobj;
744        sp->wrk->nobj = NULL;
745        sp->obj->busy = 1;
746        sp->sendbody = 1;
747        sp->step = STP_FETCH;
748        return (0);
749}
750
751/*--------------------------------------------------------------------
752 * Ship the request header to the backend unchanged, then pipe
753 * until one of the ends close the connection.
754 *
755DOT subgraph xcluster_pipe {
756DOT     pipe [
757DOT             shape=ellipse
758DOT             label="Filter req.->bereq."
759DOT     ]
760DOT     vcl_pipe [
761DOT             shape=record
762DOT             label="vcl_pipe()|req.\nbereq\."
763DOT     ]
764DOT     pipe_do [
765DOT             shape=ellipse
766DOT             label="send bereq.\npipe until close"
767DOT     ]
768DOT     vcl_pipe -> pipe_do [label="pipe",style=bold,color=orange]
769DOT     pipe -> vcl_pipe [style=bold,color=orange]
770DOT }
771DOT pipe_do -> DONE [style=bold,color=orange]
772DOT vcl_pipe -> err_pipe [label="error"]
773DOT err_pipe [label="ERROR",shape=plaintext]
774 */
775
776static int
777cnt_pipe(struct sess *sp)
778{
779
780        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
781        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
782
783        sp->acct_req.pipe++;
784        http_FilterHeader(sp, HTTPH_R_PIPE);
785
786        VCL_pipe_method(sp);
787
788        if (sp->handling == VCL_RET_ERROR)
789                INCOMPL();
790        assert(sp->handling == VCL_RET_PIPE);
791
792        PipeSession(sp);
793        AZ(sp->bereq);
794        AZ(sp->wrk->wfd);
795        sp->step = STP_DONE;
796        return (0);
797}
798
799/*--------------------------------------------------------------------
800 * RECV
801 * We have a complete request, set everything up and start it.
802 *
803DOT subgraph xcluster_recv {
804DOT     recv [
805DOT             shape=record
806DOT             label="vcl_recv()|req."
807DOT     ]
808DOT }
809DOT RESTART -> recv
810DOT recv -> pipe [label="pipe",style=bold,color=orange]
811DOT recv -> pass2 [label="pass",style=bold,color=red]
812DOT recv -> err_recv [label="error"]
813DOT err_recv [label="ERROR",shape=plaintext]
814DOT recv -> hash [label="lookup",style=bold,color=green,weight=4]
815 */
816
817static int
818cnt_recv(struct sess *sp)
819{
820
821        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
822        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
823        AZ(sp->obj);
824
825        SES_ResetBackendTimeouts(sp);
826
827        /* By default we use the first backend */
828        AZ(sp->director);
829        sp->director = sp->vcl->director[0];
830        AN(sp->director);
831
832        sp->disable_esi = 0;
833       
834        VCL_recv_method(sp);
835        if (sp->restarts >= params->max_restarts) {
836                if (sp->err_code == 0)
837                        sp->err_code = 503;
838                sp->step = STP_ERROR;
839                return (0);
840        }
841
842        sp->wantbody = (strcmp(sp->http->hd[HTTP_HDR_REQ].b, "HEAD") != 0);
843        sp->sendbody = 0;
844        switch(sp->handling) {
845        case VCL_RET_LOOKUP:
846                /* XXX: discard req body, if any */
847                sp->step = STP_LOOKUP;
848                return (0);
849        case VCL_RET_PIPE:
850                if (sp->esis > 0) {
851                        /* XXX: VSL something */
852                        INCOMPL();
853                        sp->step = STP_DONE;
854                        return (1);
855                }
856                sp->step = STP_PIPE;
857                return (0);
858        case VCL_RET_PASS:
859                sp->step = STP_PASS;
860                return (0);
861        case VCL_RET_ERROR:
862                /* XXX: discard req body, if any */
863                sp->step = STP_ERROR;
864                return (0);
865        default:
866                WRONG("Illegal action in vcl_recv{}");
867        }
868}
869
870/*--------------------------------------------------------------------
871 * START
872 * Handle a request, wherever it came from recv/restart.
873 *
874DOT start [shape=box,label="Dissect request"]
875DOT start -> recv [style=bold,color=green,weight=4]
876 */
877
878static int
879cnt_start(struct sess *sp)
880{
881        int done;
882        char *p;
883        const char *r = "HTTP/1.1 100 Continue\r\n\r\n";
884
885        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
886        AZ(sp->restarts);
887        AZ(sp->obj);
888        AZ(sp->vcl);
889
890        /* Update stats of various sorts */
891        VSL_stats->client_req++;                        /* XXX not locked */
892        sp->t_req = TIM_real();
893        sp->wrk->lastused = sp->t_req;
894        sp->acct_req.req++;
895
896        /* Assign XID and log */
897        sp->xid = ++xids;                               /* XXX not locked */
898        WSP(sp, SLT_ReqStart, "%s %s %u", sp->addr, sp->port,  sp->xid);
899
900        /* Borrow VCL reference from worker thread */
901        VCL_Refresh(&sp->wrk->vcl);
902        sp->vcl = sp->wrk->vcl;
903        sp->wrk->vcl = NULL;
904
905        http_Setup(sp->http, sp->ws);
906        done = http_DissectRequest(sp);
907
908        /* If we could not even parse the request, just close */
909        if (done < 0) {
910                sp->step = STP_DONE;
911                vca_close_session(sp, "junk");
912                return (0);
913        }
914
915        /* Catch request snapshot */
916        sp->ws_req = WS_Snapshot(sp->ws);
917
918        /* Catch original request, before modification */
919        *sp->http0 = *sp->http;
920
921        if (done != 0) {
922                sp->err_code = done;
923                sp->step = STP_ERROR;
924                return (0);
925        }
926
927        sp->doclose = http_DoConnection(sp->http);
928
929        /* XXX: Handle TRACE & OPTIONS of Max-Forwards = 0 */
930
931        /*
932         * Handle Expect headers
933         */
934        if (http_GetHdr(sp->http, H_Expect, &p)) {
935                if (strcmp(p, "100-continue")) {
936                        sp->err_code = 417;
937                        sp->step = STP_ERROR;
938                        return (0);
939                }
940
941                /* XXX: Don't bother with write failures for now */
942                (void)write(sp->fd, r, strlen(r));
943                /* XXX: When we do ESI includes, this is not removed
944                 * XXX: because we use http0 as our basis.  Believed
945                 * XXX: safe, but potentially confusing.
946                 */
947                http_Unset(sp->http, H_Expect);
948        }
949
950        sp->step = STP_RECV;
951        return (0);
952}
953
954/*--------------------------------------------------------------------
955 * Central state engine dispatcher.
956 *
957 * Kick the session around until it has had enough.
958 *
959 */
960
961static void
962cnt_diag(struct sess *sp, const char *state)
963{
964        if (sp->wrk != NULL) {
965                WSL(sp->wrk, SLT_Debug, sp->id,
966                    "thr %p STP_%s sp %p obj %p vcl %p",
967                    pthread_self(), state, sp, sp->obj, sp->vcl);
968                WSL_Flush(sp->wrk, 0);
969        } else {
970                VSL(SLT_Debug, sp->id,
971                    "thr %p STP_%s sp %p obj %p vcl %p",
972                    pthread_self(), state, sp, sp->obj, sp->vcl);
973        }
974}
975
976void
977CNT_Session(struct sess *sp)
978{
979        int done;
980        struct worker *w;
981
982        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
983        w = sp->wrk;
984        CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
985
986        /*
987         * Possible entrance states
988         */
989        assert(
990            sp->step == STP_FIRST ||
991            sp->step == STP_START ||
992            sp->step == STP_LOOKUP ||
993            sp->step == STP_RECV);
994
995        /*
996         * Whenever we come in from the acceptor we need to set blocking
997         * mode, but there is no point in setting it when we come from
998         * ESI or when a parked sessions returns.
999         * It would be simpler to do this in the acceptor, but we'd rather
1000         * do the syscall in the worker thread.
1001         */
1002        if (sp->step == STP_FIRST || sp->step == STP_START)
1003                TCP_blocking(sp->fd);
1004
1005        for (done = 0; !done; ) {
1006                assert(sp->wrk == w);
1007                /*
1008                 * This is a good place to be paranoid about the various
1009                 * pointers still pointing to the things we expect.
1010                 */
1011                CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1012                CHECK_OBJ_ORNULL(sp->obj, OBJECT_MAGIC);
1013                CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
1014                CHECK_OBJ_ORNULL(w->nobj, OBJECT_MAGIC);
1015                CHECK_OBJ_ORNULL(w->nobjhead, OBJHEAD_MAGIC);
1016
1017                switch (sp->step) {
1018#define STEP(l,u) \
1019                    case STP_##u: \
1020                        if (params->diag_bitmap & 0x01) \
1021                                cnt_diag(sp, #u); \
1022                        done = cnt_##l(sp); \
1023                        break;
1024#include "steps.h"
1025#undef STEP
1026                default:
1027                        WRONG("State engine misfire");
1028                }
1029                CHECK_OBJ_ORNULL(w->nobj, OBJECT_MAGIC);
1030                CHECK_OBJ_ORNULL(w->nobjhead, OBJHEAD_MAGIC);
1031        }
1032        WSL_Flush(w, 0);
1033        AZ(w->wfd);
1034}
1035
1036/*
1037DOT }
1038*/
1039
1040/*--------------------------------------------------------------------
1041 * Debugging aids
1042 */
1043
1044static void
1045cli_debug_xid(struct cli *cli, const char * const *av, void *priv)
1046{
1047        (void)priv;
1048        if (av[2] != NULL)
1049                xids = strtoul(av[2], NULL, 0);
1050        cli_out(cli, "XID is %u", xids);
1051}
1052
1053/*
1054 * Default to seed=1, this is the only seed value POSIXl guarantees will
1055 * result in a reproducible random number sequence.
1056 */
1057static void
1058cli_debug_srandom(struct cli *cli, const char * const *av, void *priv)
1059{
1060        (void)priv;
1061        unsigned seed = 1;
1062
1063        if (av[2] != NULL)
1064                seed = strtoul(av[2], NULL, 0);
1065        srandom(seed);
1066        cli_out(cli, "Random(3) seeded with %lu", seed);
1067}
1068
1069static struct cli_proto debug_cmds[] = {
1070        { "debug.xid", "debug.xid",
1071                "\tExamine or set XID\n", 0, 1, cli_debug_xid },
1072        { "debug.srandom", "debug.srandom",
1073                "\tSeed the random(3) function\n", 0, 1, cli_debug_srandom },
1074        { NULL }
1075};
1076
1077/*--------------------------------------------------------------------
1078 *
1079 */
1080
1081void
1082CNT_Init(void)
1083{
1084
1085        srandomdev();
1086        xids = random();
1087        CLI_AddFuncs(DEBUG_CLI, debug_cmds);
1088}
1089
1090
Note: See TracBrowser for help on using the browser.