This patch fixed the following errors in the cookie code in Flood: (1) Original code only handled a single "set-cookie" header for a given HTTP message. There can be more than one. (2) Original code did not handle a replacement for a cookie value already in the "database". The fix searches through and avoids these duplicates by replacing.
Please examine the attached diff and apply the changes to the file flood_round_robin.c to resolve these issues. -Norman Tuttle, developer, OpenDemand Systems, [EMAIL PROTECTED]
--- flood_round_robin.c 2003-10-20 11:37:20.000000000 -0400 +++ \flood-1.1\flood_round_robin.c 2003-09-07 22:22:32.000000000 -0400 @@ -151,14 +151,14 @@ } round_robin_profile_t; -static char *handle_param_string(round_robin_profile_t *rp, char *template, +static char *handle_param_string(round_robin_profile_t *rp, char *template, expand_param_e set) { char *cpy, *cur, *prev, *data, *returnValue, *pattern; int size, matchsize; regex_t re; regmatch_t match[2]; - + prev = template; returnValue = NULL; @@ -203,7 +203,7 @@ /* If there is no data, place the original string back. */ if (!data) { - data = apr_psprintf(rp->pool, "${%s}", + data = apr_psprintf(rp->pool, "${%s}", apr_pstrmemdup(rp->pool, cur+match[1].rm_so, match[1].rm_eo - match[1].rm_so)); } @@ -218,11 +218,11 @@ else { if (cpy) - returnValue = apr_pstrcat(rp->pool, returnValue, cpy, data, + returnValue = apr_pstrcat(rp->pool, returnValue, cpy, data, NULL); else returnValue = apr_pstrcat(rp->pool, returnValue, data, NULL); - + } /* Skip over the trailing } */ @@ -255,8 +255,8 @@ char *cookies; char *enc_credtls, *credtls, *authz_hdr = NULL; cookie_t *cook; - - p = (round_robin_profile_t*)profile; + + p = (round_robin_profile_t*)profile; /* Do we want to save the entire response? */ r->wantresponse = p->url[p->current_url].responsetemplate ? 1 : 0; @@ -271,9 +271,9 @@ if (cook != p->cookie) cookies = apr_pstrcat(p->pool, cookies, ";", NULL); - cookies = apr_pstrcat(p->pool, cookies, cook->name, "=", + cookies = apr_pstrcat(p->pool, cookies, cook->name, "=", cook->value, NULL); - cook = cook->next; + cook = cook->next; } cookies = apr_pstrcat(p->pool, cookies, CRLF, NULL); } @@ -302,14 +302,14 @@ switch (r->method) { case GET: - r->rbuf = apr_psprintf(r->pool, + r->rbuf = apr_psprintf(r->pool, "GET %s%s%s HTTP/1.1" CRLF "User-Agent: Flood/" FLOOD_VERSION CRLF "Connection: %s" CRLF - "Host: %s" CRLF + "Host: %s" CRLF "%s" "%s" CRLF, - r->parsed_uri->path, + r->parsed_uri->path, r->parsed_uri->query ? "?" : "", r->parsed_uri->query ? r->parsed_uri->query : "", r->keepalive ? "Keep-Alive" : "Close", @@ -320,14 +320,14 @@ r->rbufsize = strlen(r->rbuf); break; case HEAD: - r->rbuf = apr_psprintf(r->pool, + r->rbuf = apr_psprintf(r->pool, "HEAD %s%s%s HTTP/1.1" CRLF "User-Agent: Flood/" FLOOD_VERSION CRLF "Connection: %s" CRLF - "Host: %s" CRLF + "Host: %s" CRLF "%s" "%s" CRLF, - r->parsed_uri->path, + r->parsed_uri->path, r->parsed_uri->query ? "?" : "", r->parsed_uri->query ? r->parsed_uri->query : "", r->keepalive ? "Keep-Alive" : "Close", @@ -340,17 +340,17 @@ case POST: /* FIXME */ if (r->payload) { - r->rbuf = apr_psprintf(r->pool, + r->rbuf = apr_psprintf(r->pool, "POST %s%s%s HTTP/1.1" CRLF "User-Agent: Flood/" FLOOD_VERSION CRLF "Connection: %s" CRLF "Host: %s" CRLF - "Content-Length: %d" CRLF + "Content-Length: %d" CRLF "Content-type: application/x-www-form-urlencoded" CRLF "%s" "%s" CRLF "%s", - r->parsed_uri->path, + r->parsed_uri->path, r->parsed_uri->query ? "?" : "", r->parsed_uri->query ? r->parsed_uri->query : "", r->keepalive ? "Keep-Alive" : "Close", @@ -360,7 +360,7 @@ cookies, (char*)r->payload); } else { /* There is no payload, but it's still a POST */ - r->rbuf = apr_psprintf(r->pool, + r->rbuf = apr_psprintf(r->pool, "POST %s%s%s HTTP/1.1" CRLF "User-Agent: Flood/" FLOOD_VERSION CRLF "Connection: %s" CRLF @@ -368,7 +368,7 @@ "%s" "%s" CRLF "", - r->parsed_uri->path, + r->parsed_uri->path, r->parsed_uri->query ? "?" : "", r->parsed_uri->query ? r->parsed_uri->query : "", r->keepalive ? "Keep-Alive" : "Close", @@ -393,7 +393,7 @@ if (e->first_cdata.first->next) { apr_text *t; - t = e->first_cdata.first; + t = e->first_cdata.first; url->url = apr_pstrdup(pool, t->text); while ((t = t->next)) { @@ -411,7 +411,7 @@ apr_xml_attr *attr = e->attr; while (attr) { - if (strncasecmp(attr->name, XML_URLLIST_METHOD, + if (strncasecmp(attr->name, XML_URLLIST_METHOD, FLOOD_STRLEN_MAX) == 0) { if (strncasecmp(attr->value, XML_URLLIST_METHOD_POST, 4) == 0) url->method = POST; @@ -428,7 +428,7 @@ return APR_EGENERAL; } } - else if (strncasecmp(attr->name, XML_URLLIST_PAYLOAD, + else if (strncasecmp(attr->name, XML_URLLIST_PAYLOAD, FLOOD_STRLEN_MAX) == 0) { url->payload = (char*)attr->value; } @@ -438,7 +438,7 @@ url->predelay = strtoll(attr->value, &endptr, 10); if (*endptr != '\0') { - apr_file_printf(local_stderr, + apr_file_printf(local_stderr, "Attribute %s has invalid value %s.\n", XML_URLLIST_PREDELAY, attr->value); return APR_EGENERAL; @@ -464,7 +464,7 @@ url->postdelay = strtoll(attr->value, &endptr, 10); if (*endptr != '\0') { - apr_file_printf(local_stderr, + apr_file_printf(local_stderr, "Attribute %s has invalid value %s.\n", XML_URLLIST_POSTDELAY, attr->value); return APR_EGENERAL; @@ -484,38 +484,38 @@ } url->postdelayprecision *= APR_USEC_PER_SEC; } - else if (strncasecmp(attr->name, - XML_URLLIST_PAYLOAD_TEMPLATE, + else if (strncasecmp(attr->name, + XML_URLLIST_PAYLOAD_TEMPLATE, FLOOD_STRLEN_MAX) == 0) { url->payloadtemplate = (char*)attr->value; } - else if (strncasecmp(attr->name, - XML_URLLIST_REQUEST_TEMPLATE, + else if (strncasecmp(attr->name, + XML_URLLIST_REQUEST_TEMPLATE, FLOOD_STRLEN_MAX) == 0) { url->requesttemplate = (char*)attr->value; } - else if (strncasecmp(attr->name, - XML_URLLIST_RESPONSE_TEMPLATE, + else if (strncasecmp(attr->name, + XML_URLLIST_RESPONSE_TEMPLATE, FLOOD_STRLEN_MAX) == 0) { url->responsetemplate = (char*)attr->value; } - else if (strncasecmp(attr->name, - XML_URLLIST_RESPONSE_SCRIPT, + else if (strncasecmp(attr->name, + XML_URLLIST_RESPONSE_SCRIPT, FLOOD_STRLEN_MAX) == 0) { url->responsescript = (char*)attr->value; } - else if (strncasecmp(attr->name, + else if (strncasecmp(attr->name, XML_URLLIST_RESPONSE_NAME, FLOOD_STRLEN_MAX) == 0) { url->responsename = (char*)attr->value; url->responselen = strlen((char*)attr->value); } - else if (strncasecmp(attr->name, + else if (strncasecmp(attr->name, XML_URLLIST_USER, FLOOD_STRLEN_MAX) == 0) { url->user = (char*)attr->value; } - else if (strncasecmp(attr->name, + else if (strncasecmp(attr->name, XML_URLLIST_PASSWORD, FLOOD_STRLEN_MAX) == 0) { url->password = (char*)attr->value; @@ -531,7 +531,7 @@ return APR_SUCCESS; } - + static apr_status_t parse_xml_seq_info(apr_xml_elem *e, round_robin_profile_t *p, apr_pool_t *pool) @@ -548,8 +548,8 @@ FLOOD_STRLEN_MAX) == 0) { seqname = (char*)attr->value; seqnamelen = strlen(seqname); - } - else if (strncasecmp(attr->name, + } + else if (strncasecmp(attr->name, XML_URLLIST_SEQUENCE_LIST, FLOOD_STRLEN_MAX) == 0) { /* FIXME: ap_getword needs to be in apr-util! */ @@ -559,14 +559,14 @@ while (*end && (end = strchr(end, ','))) { count++; end++; - } + } seqlist = apr_palloc(pool, sizeof(char*) * count); seqcount = count; cur = (char*)attr->value; end = strchr(cur, ','); for (num = 0; num < count; num++) { - while (apr_isspace(*cur)) { + while (apr_isspace(*cur)) { cur++; } if (end) { @@ -579,10 +579,10 @@ seqlist[num] = apr_pstrdup(pool, cur); } } - } - attr = attr->next; + } + attr = attr->next; } - } + } for (curseq = 0; curseq < seqcount; curseq++) { apr_hash_set(p->state, seqname, seqnamelen, seqlist[curseq]); for (child_url_elem = e->first_child; child_url_elem; @@ -604,19 +604,19 @@ } /* Expand them. */ if (p->url[p->current_url].payloadtemplate) { - p->url[p->current_url].payloadtemplate = + p->url[p->current_url].payloadtemplate = handle_param_string(p, p->url[p->current_url].payloadtemplate, EPE_PASSTHROUGH); } if (p->url[p->current_url].requesttemplate) { - p->url[p->current_url].requesttemplate = + p->url[p->current_url].requesttemplate = handle_param_string(p, p->url[p->current_url].requesttemplate, EPE_PASSTHROUGH); } if (p->url[p->current_url].responsetemplate) { - p->url[p->current_url].responsetemplate = + p->url[p->current_url].responsetemplate = handle_param_string(p, p->url[p->current_url].responsetemplate, EPE_PASSTHROUGH); @@ -640,7 +640,7 @@ if (e->attr) { apr_xml_attr *attr = e->attr; while (attr) { - if (strncasecmp(attr->name, + if (strncasecmp(attr->name, XML_URLLIST_SEQUENCE_LIST, FLOOD_STRLEN_MAX) == 0) { char *end = (char*)attr->value; @@ -715,7 +715,7 @@ apr_file_printf(local_stderr, "Profile '%s' has element <%s> with no value, assuming 1.\n", profile_name, XML_PROFILE_COUNT); - p->execute_rounds = 1; + p->execute_rounds = 1; } } @@ -800,16 +800,16 @@ if (rp->url[rp->current_url].requesttemplate) { - r->uri = parse_param_string(rp, + r->uri = parse_param_string(rp, rp->url[rp->current_url].requesttemplate); } else r->uri = rp->url[rp->current_url].url; - + r->method = rp->url[rp->current_url].method; /* We're created by calloc, so no need to set payload to be null or - * payloadsize to be 0. + * payloadsize to be 0. */ if (rp->url[rp->current_url].payload) { @@ -818,7 +818,7 @@ } else if (rp->url[rp->current_url].payloadtemplate) { - r->payload = parse_param_string(rp, + r->payload = parse_param_string(rp, rp->url[rp->current_url].payloadtemplate); r->payloadsize = strlen(r->payload); } @@ -877,7 +877,7 @@ } if (!r->parsed_uri->port) { - r->parsed_uri->port = + r->parsed_uri->port = apr_uri_default_port_for_scheme(r->parsed_uri->scheme); } if (!r->parsed_uri->path) /* If / is not there, be nice. */ @@ -897,70 +897,43 @@ response_t *resp) { round_robin_profile_t *rp; - char *cookieheader, *cookievalue, *cookieend, *respend; - unsigned size; + char *cookieheader, *cookievalue, *cookieend; rp = (round_robin_profile_t*)profile; - cookieend = resp->rbuf; /* sets next search point to beginning of rbuf */ - respend = cookieend + resp->rbufsize; /* response ends at end of rbuf */ - - /*-----------------6/30/2003 0:15AM----------------- - * Improved this code a little. Now handles multiple cookies - NT - * Also will properly handle case of replacing cookies. - * The current search may still find false positives. - * --------------------------------------------------*/ - while ((cookieheader = strstr(cookieend, "Set-Cookie: ")) != NULL) - { /* The while handles the poss. of >1 Set-Cookie! */ - /* Point to the value */ - cookieheader += 12; - cookievalue = (char*) memchr(cookieheader, '=', respend - cookieheader); - if (cookievalue) - { - cookie_t *cookie = NULL, *cook = rp->cookie; - - size = cookievalue - cookieheader; - while (cook) - { - if ((strlen(cook->name)==size)&& - (!strncasecmp(cookieheader, cook->name, size))) - { /* Size check needed because one name may be subset of other */ - cookie = cook; /* found cookie, exit loop */ - break; - } - cook = cook -> next; - } - if (!cookie) /* at this point same as saying (!cook) */ - { - cookie = apr_pcalloc(rp->pool, sizeof(cookie_t)); - cookie->name = apr_palloc(rp->pool, ++size); - /* bump up size for null termination */ - apr_cpystrn(cookie->name, cookieheader, size); - } - - cookieheader = cookievalue + 1; - cookieend = (char*) memchr(cookieheader, '\r', respend - cookieheader); - /* above calculation derives REAL cookieend */ - if (!cookieend) /* This should not be happening. */ - break; /* Stop cookie search now! Drop current attempt! */ - cookievalue = (char*) memchr(cookieheader, ';', cookieend - cookieheader); - /* First using REAL cookieend! */ - if (!cookievalue) - cookievalue = cookieend; - size = cookievalue + 1 - cookieheader; - /* !cook: If exited while loop above without finding cookie match, - * then value wasn't previously set. */ - if ((!cook)||(size > strlen(cookie->value)+1)) - { - cookie->value = apr_palloc(rp->pool, size); - } - apr_cpystrn(cookie->value, cookieheader, size); /* copy in new value */ - if (!cook) /* if cookie wasn't in linked list, put it in now! */ + /* FIXME: This algorithm sucks. I need to be shot for writing such + * atrocious code. Grr. */ + cookieheader = strstr(resp->rbuf, "Set-Cookie: "); + if (cookieheader) + { + /* Point to the value */ + cookieheader += 12; + cookievalue = (char*) memchr(cookieheader, '=', + resp->rbufsize - (int)(cookieheader - (int)(resp->rbuf))); + if (cookievalue) { - cookie->next = rp->cookie; - rp->cookie = cookie; + cookie_t * cookie = apr_pcalloc(rp->pool, sizeof(cookie_t)); + + ++cookievalue; + cookie->name = apr_palloc(rp->pool, cookievalue - cookieheader); + apr_cpystrn(cookie->name, cookieheader, cookievalue - cookieheader); + + cookieheader = cookievalue; + cookieend = (char*) memchr(cookieheader, '\r', + resp->rbufsize - (int)(cookieheader - (int)(resp->rbuf))); + cookievalue = (char*) memchr(cookieheader, ';', + cookieend - cookieheader); + if (!cookievalue) + cookievalue = cookieend; + + ++cookievalue; + + cookie->value = apr_palloc(rp->pool, cookievalue - cookieheader); + apr_cpystrn(cookie->value, cookieheader, + cookievalue - cookieheader); + cookie->next = rp->cookie; + rp->cookie = cookie; } - } } if (rp->url[rp->current_url].responsetemplate) { @@ -969,7 +942,7 @@ regmatch_t match[10]; regex_t re; - expanded = expand_param_string(rp, + expanded = expand_param_string(rp, rp->url[rp->current_url].responsetemplate); regcomp(&re, expanded, REG_EXTENDED); status = regexec(&re, resp->rbuf, 10, match, 0); @@ -1001,7 +974,7 @@ char **args; const char *progname; - + if ((rv = apr_procattr_create(&procattr, rp->pool)) != APR_SUCCESS) { apr_file_printf(local_stderr, @@ -1169,7 +1142,7 @@ /* Adjust counters for profile */ if (rp->current_url >= rp->urls) { rp->current_url = 0; - + /* Loop cond tells us when to stop. */ rp->current_round++; } @@ -1183,7 +1156,7 @@ if (rp->current_round >= rp->execute_rounds) return 0; else { /* we'll continue, so do delay stuff now if necessary */ - + /* If they want a sleep, do it now. */ if (rp->url[real_current_url].postdelay) { apr_int64_t real_postdelay = rp->url[real_current_url].postdelay;