~ubuntu-branches/ubuntu/trusty/haproxy/trusty-backports

« back to all changes in this revision

Viewing changes to src/proto_http.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Cornet
  • Date: 2010-06-18 00:42:53 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20100618004253-ygka2bh6nblkhfj2
Tags: 1.4.8-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
49
49
#include <proto/fd.h>
50
50
#include <proto/log.h>
51
51
#include <proto/hdr_idx.h>
 
52
#include <proto/pattern.h>
52
53
#include <proto/proto_tcp.h>
53
54
#include <proto/proto_http.h>
54
55
#include <proto/proxy.h>
2408
2409
        /* 1: we might have to print this header in debug mode */
2409
2410
        if (unlikely((global.mode & MODE_DEBUG) &&
2410
2411
                     (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
 
2412
                     msg->sol &&
2411
2413
                     (msg->msg_state >= HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
2412
2414
                char *eol, *sol;
2413
2415
 
2414
 
                sol = msg->sol;
 
2416
                sol = req->data + msg->som;
2415
2417
                eol = sol + msg->sl.rq.l;
2416
2418
                debug_hdr("clireq", s, sol, eol);
2417
2419
 
3282
3284
         * so let's do the same now.
3283
3285
         */
3284
3286
 
3285
 
        /* It needs to look into the URI */
3286
 
        if ((txn->sessid == NULL) && s->be->appsession_name) {
 
3287
        /* It needs to look into the URI unless persistence must be ignored */
 
3288
        if ((txn->sessid == NULL) && s->be->appsession_name && !(s->flags & SN_IGNORE_PRST)) {
3287
3289
                get_srv_from_appsession(s, msg->sol + msg->sl.rq.u, msg->sl.rq.u_l);
3288
3290
        }
3289
3291
 
3601
3603
        if ((req->flags & BF_READ_TIMEOUT) || tick_is_expired(req->analyse_exp, now_ms)) {
3602
3604
                txn->status = 408;
3603
3605
                stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_408));
 
3606
 
 
3607
                if (!(s->flags & SN_ERR_MASK))
 
3608
                        s->flags |= SN_ERR_CLITO;
 
3609
                if (!(s->flags & SN_FINST_MASK))
 
3610
                        s->flags |= SN_FINST_D;
3604
3611
                goto return_err_msg;
3605
3612
        }
3606
3613
 
3630
3637
        txn->status = 400;
3631
3638
        stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
3632
3639
 
 
3640
        if (!(s->flags & SN_ERR_MASK))
 
3641
                s->flags |= SN_ERR_PRXCOND;
 
3642
        if (!(s->flags & SN_FINST_MASK))
 
3643
                s->flags |= SN_FINST_R;
 
3644
 
3633
3645
 return_err_msg:
3634
3646
        req->analysers = 0;
3635
3647
        s->fe->counters.failed_req++;
3636
3648
        if (s->listener->counters)
3637
3649
                s->listener->counters->failed_req++;
3638
 
 
3639
 
        if (!(s->flags & SN_ERR_MASK))
3640
 
                s->flags |= SN_ERR_PRXCOND;
3641
 
        if (!(s->flags & SN_FINST_MASK))
3642
 
                s->flags |= SN_FINST_R;
3643
3650
        return 0;
3644
3651
}
3645
3652
 
3730
3737
        s->req->cons->flags     = SI_FL_NONE;
3731
3738
        s->req->flags &= ~(BF_SHUTW|BF_SHUTW_NOW|BF_AUTO_CONNECT|BF_WRITE_ERROR|BF_STREAMER|BF_STREAMER_FAST);
3732
3739
        s->rep->flags &= ~(BF_SHUTR|BF_SHUTR_NOW|BF_READ_ATTACHED|BF_READ_ERROR|BF_READ_NOEXP|BF_STREAMER|BF_STREAMER_FAST|BF_WRITE_PARTIAL);
3733
 
        s->flags &= ~(SN_DIRECT|SN_ASSIGNED|SN_ADDR_SET|SN_BE_ASSIGNED|SN_FORCE_PRST);
 
3740
        s->flags &= ~(SN_DIRECT|SN_ASSIGNED|SN_ADDR_SET|SN_BE_ASSIGNED|SN_FORCE_PRST|SN_IGNORE_PRST);
3734
3741
        s->flags &= ~(SN_CURR_SESS|SN_REDIRECTABLE);
3735
3742
        s->txn.meth = 0;
3736
3743
        http_reset_txn(s);
4214
4221
 
4215
4222
 missing_data:
4216
4223
        /* stop waiting for data if the input is closed before the end */
4217
 
        if (req->flags & BF_SHUTR)
 
4224
        if (req->flags & BF_SHUTR) {
 
4225
                if (!(s->flags & SN_ERR_MASK))
 
4226
                        s->flags |= SN_ERR_CLICL;
 
4227
                if (!(s->flags & SN_FINST_MASK))
 
4228
                        s->flags |= SN_FINST_D;
4218
4229
                goto return_bad_req;
 
4230
        }
4219
4231
 
4220
4232
        /* waiting for the last bits to leave the buffer */
4221
 
        if (req->flags & BF_SHUTW)
 
4233
        if (req->flags & BF_SHUTW) {
 
4234
                if (!(s->flags & SN_ERR_MASK))
 
4235
                        s->flags |= SN_ERR_SRVCL;
 
4236
                if (!(s->flags & SN_FINST_MASK))
 
4237
                        s->flags |= SN_FINST_D;
4222
4238
                goto return_bad_req;
 
4239
        }
4223
4240
 
4224
4241
        http_silent_debug(__LINE__, s);
4225
4242
        return 0;
4312
4329
        /* 1: we might have to print this header in debug mode */
4313
4330
        if (unlikely((global.mode & MODE_DEBUG) &&
4314
4331
                     (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
 
4332
                     msg->sol &&
4315
4333
                     (msg->msg_state >= HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
4316
4334
                char *eol, *sol;
4317
4335
 
4318
 
                sol = msg->sol;
4319
 
                eol = sol + msg->sl.rq.l;
 
4336
                sol = rep->data + msg->som;
 
4337
                eol = sol + msg->sl.st.l;
4320
4338
                debug_hdr("srvrep", s, sol, eol);
4321
4339
 
4322
4340
                sol += hdr_idx_first_pos(&txn->hdr_idx);
4490
4508
        n = msg->sol[msg->sl.st.c] - '0';
4491
4509
        if (n < 1 || n > 5)
4492
4510
                n = 0;
4493
 
        s->srv->counters.p.http.rsp[n]++;
 
4511
        if (s->srv)
 
4512
                s->srv->counters.p.http.rsp[n]++;
4494
4513
 
4495
4514
        /* check if the response is HTTP/1.1 or above */
4496
4515
        if ((msg->sl.st.v_l == 8) &&
4511
4530
         * and 505 are triggered on demand by client request, so we must not
4512
4531
         * count them as server failures.
4513
4532
         */
4514
 
        if (txn->status >= 100 && (txn->status < 500 || txn->status == 501 || txn->status == 505))
4515
 
                health_adjust(s->srv, HANA_STATUS_HTTP_OK);
4516
 
        else
4517
 
                health_adjust(s->srv, HANA_STATUS_HTTP_STS);
 
4533
        if (s->srv) {
 
4534
                if (txn->status >= 100 && (txn->status < 500 || txn->status == 501 || txn->status == 505))
 
4535
                        health_adjust(s->srv, HANA_STATUS_HTTP_OK);
 
4536
                else
 
4537
                        health_adjust(s->srv, HANA_STATUS_HTTP_STS);
 
4538
        }
4518
4539
 
4519
4540
        /*
4520
4541
         * 2: check for cacheability.
4856
4877
                 * 6: add server cookie in the response if needed
4857
4878
                 */
4858
4879
                if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
4859
 
                    (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
 
4880
                    (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST)) &&
 
4881
                    !(t->flags & SN_IGNORE_PRST)) {
4860
4882
                        int len;
4861
4883
 
4862
4884
                        /* the server is known, it's not the one the client requested, we have to
5493
5515
 
5494
5516
                if (asession->serverid != NULL) {
5495
5517
                        struct server *srv = t->be->srv;
 
5518
 
5496
5519
                        while (srv) {
5497
5520
                                if (strcmp(srv->id, asession->serverid) == 0) {
5498
5521
                                        if ((srv->state & SRV_RUNNING) ||
5686
5709
                                         * However, to prevent clients from sticking to cookie-less backup server
5687
5710
                                         * when they have incidentely learned an empty cookie, we simply ignore
5688
5711
                                         * empty cookies and mark them as invalid.
 
5712
                                         * The same behaviour is applied when persistence must be ignored.
5689
5713
                                         */
5690
 
                                        if (delim == p3)
 
5714
                                        if ((delim == p3) || (t->flags & SN_IGNORE_PRST))
5691
5715
                                                srv = NULL;
5692
5716
 
5693
5717
                                        while (srv) {
5765
5789
                                        }
5766
5790
                                }
5767
5791
 
5768
 
                                if (t->be->appsession_name != NULL) {
 
5792
                                /* Look for the appsession cookie unless persistence must be ignored */
 
5793
                                if (!(t->flags & SN_IGNORE_PRST) && (t->be->appsession_name != NULL)) {
5769
5794
                                        int cmp_len, value_len;
5770
5795
                                        char *value_begin;
5771
5796
 
5950
5975
        done = 0;
5951
5976
 
5952
5977
        cur_ptr = txn->rsp.sol;
5953
 
        cur_end = cur_ptr + txn->rsp.sl.rq.l;
 
5978
        cur_end = cur_ptr + txn->rsp.sl.st.l;
5954
5979
 
5955
5980
        /* Now we have the status line between cur_ptr and cur_end */
5956
5981
 
5996
6021
                         * or an LF at <ptr>.
5997
6022
                         */
5998
6023
                        txn->status = strl2ui(txn->rsp.sol + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
5999
 
                        hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.rq.l, *cur_end == '\r');
 
6024
                        hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.st.l, *cur_end == '\r');
6000
6025
                        /* there is no point trying this regex on headers */
6001
6026
                        return 1;
6002
6027
                }
6161
6186
                        }
6162
6187
 
6163
6188
                        /* now check if we need to process it for persistence */
6164
 
                        if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
 
6189
                        if (!(t->flags & SN_IGNORE_PRST) && (p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
6165
6190
                            (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
6166
6191
                                /* Cool... it's the right one */
6167
6192
                                txn->flags |= TX_SCK_SEEN;
6208
6233
                                        txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
6209
6234
                                }
6210
6235
                        }
6211
 
                        /* next, let's see if the cookie is our appcookie */
6212
 
                        else if (t->be->appsession_name != NULL) {
 
6236
                        /* next, let's see if the cookie is our appcookie, unless persistence must be ignored */
 
6237
                        else if (!(t->flags & SN_IGNORE_PRST) && (t->be->appsession_name != NULL)) {
6213
6238
                                int cmp_len, value_len;
6214
6239
                                char *value_begin;
6215
6240
 
7354
7379
        { "req_proto_http", acl_parse_nothing, acl_fetch_proto_http, acl_match_nothing, ACL_USE_L7REQ_PERMANENT },
7355
7380
 
7356
7381
        { "method",     acl_parse_meth,  acl_fetch_meth,   acl_match_meth, ACL_USE_L7REQ_PERMANENT },
7357
 
        { "req_ver",    acl_parse_ver,   acl_fetch_rqver,  acl_match_str,  ACL_USE_L7REQ_VOLATILE  },
7358
 
        { "resp_ver",   acl_parse_ver,   acl_fetch_stver,  acl_match_str,  ACL_USE_L7RTR_VOLATILE  },
 
7382
        { "req_ver",    acl_parse_ver,   acl_fetch_rqver,  acl_match_str,  ACL_USE_L7REQ_VOLATILE|ACL_MAY_LOOKUP },
 
7383
        { "resp_ver",   acl_parse_ver,   acl_fetch_stver,  acl_match_str,  ACL_USE_L7RTR_VOLATILE|ACL_MAY_LOOKUP },
7359
7384
        { "status",     acl_parse_int,   acl_fetch_stcode, acl_match_int,  ACL_USE_L7RTR_PERMANENT },
7360
7385
 
7361
 
        { "url",        acl_parse_str,   acl_fetch_url,      acl_match_str,  ACL_USE_L7REQ_VOLATILE },
 
7386
        { "url",        acl_parse_str,   acl_fetch_url,      acl_match_str,  ACL_USE_L7REQ_VOLATILE|ACL_MAY_LOOKUP },
7362
7387
        { "url_beg",    acl_parse_str,   acl_fetch_url,      acl_match_beg,  ACL_USE_L7REQ_VOLATILE },
7363
7388
        { "url_end",    acl_parse_str,   acl_fetch_url,      acl_match_end,  ACL_USE_L7REQ_VOLATILE },
7364
7389
        { "url_sub",    acl_parse_str,   acl_fetch_url,      acl_match_sub,  ACL_USE_L7REQ_VOLATILE },
7365
7390
        { "url_dir",    acl_parse_str,   acl_fetch_url,      acl_match_dir,  ACL_USE_L7REQ_VOLATILE },
7366
7391
        { "url_dom",    acl_parse_str,   acl_fetch_url,      acl_match_dom,  ACL_USE_L7REQ_VOLATILE },
7367
7392
        { "url_reg",    acl_parse_reg,   acl_fetch_url,      acl_match_reg,  ACL_USE_L7REQ_VOLATILE },
7368
 
        { "url_ip",     acl_parse_ip,    acl_fetch_url_ip,   acl_match_ip,   ACL_USE_L7REQ_VOLATILE },
 
7393
        { "url_ip",     acl_parse_ip,    acl_fetch_url_ip,   acl_match_ip,   ACL_USE_L7REQ_VOLATILE|ACL_MAY_LOOKUP },
7369
7394
        { "url_port",   acl_parse_int,   acl_fetch_url_port, acl_match_int,  ACL_USE_L7REQ_VOLATILE },
7370
7395
 
7371
7396
        /* note: we should set hdr* to use ACL_USE_HDR_VOLATILE, and chdr* to use L7REQ_VOLATILE */
7372
 
        { "hdr",        acl_parse_str,   acl_fetch_chdr,    acl_match_str, ACL_USE_L7REQ_VOLATILE },
 
7397
        { "hdr",        acl_parse_str,   acl_fetch_chdr,    acl_match_str, ACL_USE_L7REQ_VOLATILE|ACL_MAY_LOOKUP },
7373
7398
        { "hdr_reg",    acl_parse_reg,   acl_fetch_chdr,    acl_match_reg, ACL_USE_L7REQ_VOLATILE },
7374
7399
        { "hdr_beg",    acl_parse_str,   acl_fetch_chdr,    acl_match_beg, ACL_USE_L7REQ_VOLATILE },
7375
7400
        { "hdr_end",    acl_parse_str,   acl_fetch_chdr,    acl_match_end, ACL_USE_L7REQ_VOLATILE },
7378
7403
        { "hdr_dom",    acl_parse_str,   acl_fetch_chdr,    acl_match_dom, ACL_USE_L7REQ_VOLATILE },
7379
7404
        { "hdr_cnt",    acl_parse_int,   acl_fetch_chdr_cnt,acl_match_int, ACL_USE_L7REQ_VOLATILE },
7380
7405
        { "hdr_val",    acl_parse_int,   acl_fetch_chdr_val,acl_match_int, ACL_USE_L7REQ_VOLATILE },
7381
 
        { "hdr_ip",     acl_parse_ip,    acl_fetch_chdr_ip, acl_match_ip,  ACL_USE_L7REQ_VOLATILE },
 
7406
        { "hdr_ip",     acl_parse_ip,    acl_fetch_chdr_ip, acl_match_ip,  ACL_USE_L7REQ_VOLATILE|ACL_MAY_LOOKUP },
7382
7407
 
7383
 
        { "shdr",       acl_parse_str,   acl_fetch_shdr,    acl_match_str, ACL_USE_L7RTR_VOLATILE },
 
7408
        { "shdr",       acl_parse_str,   acl_fetch_shdr,    acl_match_str, ACL_USE_L7RTR_VOLATILE|ACL_MAY_LOOKUP },
7384
7409
        { "shdr_reg",   acl_parse_reg,   acl_fetch_shdr,    acl_match_reg, ACL_USE_L7RTR_VOLATILE },
7385
7410
        { "shdr_beg",   acl_parse_str,   acl_fetch_shdr,    acl_match_beg, ACL_USE_L7RTR_VOLATILE },
7386
7411
        { "shdr_end",   acl_parse_str,   acl_fetch_shdr,    acl_match_end, ACL_USE_L7RTR_VOLATILE },
7389
7414
        { "shdr_dom",   acl_parse_str,   acl_fetch_shdr,    acl_match_dom, ACL_USE_L7RTR_VOLATILE },
7390
7415
        { "shdr_cnt",   acl_parse_int,   acl_fetch_shdr_cnt,acl_match_int, ACL_USE_L7RTR_VOLATILE },
7391
7416
        { "shdr_val",   acl_parse_int,   acl_fetch_shdr_val,acl_match_int, ACL_USE_L7RTR_VOLATILE },
7392
 
        { "shdr_ip",    acl_parse_ip,    acl_fetch_shdr_ip, acl_match_ip,  ACL_USE_L7RTR_VOLATILE },
 
7417
        { "shdr_ip",    acl_parse_ip,    acl_fetch_shdr_ip, acl_match_ip,  ACL_USE_L7RTR_VOLATILE|ACL_MAY_LOOKUP },
7393
7418
 
7394
 
        { "path",       acl_parse_str,   acl_fetch_path,   acl_match_str, ACL_USE_L7REQ_VOLATILE },
 
7419
        { "path",       acl_parse_str,   acl_fetch_path,   acl_match_str, ACL_USE_L7REQ_VOLATILE|ACL_MAY_LOOKUP },
7395
7420
        { "path_reg",   acl_parse_reg,   acl_fetch_path,   acl_match_reg, ACL_USE_L7REQ_VOLATILE },
7396
7421
        { "path_beg",   acl_parse_str,   acl_fetch_path,   acl_match_beg, ACL_USE_L7REQ_VOLATILE },
7397
7422
        { "path_end",   acl_parse_str,   acl_fetch_path,   acl_match_end, ACL_USE_L7REQ_VOLATILE },
7423
7448
        { NULL, NULL, NULL, NULL },
7424
7449
}};
7425
7450
 
 
7451
/************************************************************************/
 
7452
/*     The code below is dedicated to pattern fetching and matching     */
 
7453
/************************************************************************/
 
7454
 
 
7455
/* extract the IP address from the last occurrence of specified header. Note
 
7456
 * that we should normally first extract the string then convert it to IP,
 
7457
 * but right now we have all the functions to do this seemlessly, and we will
 
7458
 * be able to change that later without touching the configuration.
 
7459
 */
 
7460
static int
 
7461
pattern_fetch_hdr_ip(struct proxy *px, struct session *l4, void *l7, int dir,
 
7462
                  const char *arg, int arg_len, union pattern_data *data)
 
7463
{
 
7464
        struct http_txn *txn = l7;
 
7465
 
 
7466
        data->ip.s_addr = htonl(get_ip_from_hdr2(&txn->req, arg, arg_len, &txn->hdr_idx, -1));
 
7467
        return data->ip.s_addr != 0;
 
7468
}
 
7469
 
 
7470
/************************************************************************/
 
7471
/*             All supported keywords must be declared here.            */
 
7472
/************************************************************************/
 
7473
/* Note: must not be declared <const> as its list will be overwritten */
 
7474
static struct pattern_fetch_kw_list pattern_fetch_keywords = {{ },{
 
7475
        { "hdr",       pattern_fetch_hdr_ip,   PATTERN_TYPE_IP,   PATTERN_FETCH_REQ },
 
7476
        { NULL, NULL, 0, 0 },
 
7477
}};
 
7478
 
7426
7479
 
7427
7480
__attribute__((constructor))
7428
7481
static void __http_protocol_init(void)
7429
7482
{
7430
7483
        acl_register_keywords(&acl_kws);
 
7484
        pattern_register_fetches(&pattern_fetch_keywords);
7431
7485
}
7432
7486
 
7433
7487