static void print_reply_hdr (Call *call, const char *buf, int len) { Call_Private_Data *priv = CALL_PRIVATE_DATA (call); const char *eoh; if (len <= 0 || priv->done_with_reply_hdr) return; eoh = strstr (buf, "\r\n\r\n"); if (eoh) { priv->done_with_reply_hdr = 1; eoh += 4; } else { /* no CRLFCRLF: non-conforming server */ eoh = strstr (buf, "\n\n"); if (eoh) { priv->done_with_reply_hdr = 1; eoh += 2; } else eoh = buf + len; } print_buf (call, "RH", buf, eoh - buf); }
static void call_recv_hdr (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg) { Call_Private_Data *cpriv; Sess_Private_Data *priv; struct iovec *line; Call *call; Sess *sess; char *hdr; assert (et == EV_CALL_RECV_HDR && object_is_call (obj)); call = (Call *) obj; cpriv = CALL_PRIVATE_DATA (call); sess = session_get_sess_from_call (call); priv = SESS_PRIVATE_DATA (sess); line = callarg.vp; hdr = line->iov_base; switch (tolower (hdr[0])) { case 'c': if (line->iov_len >= 23 && strncasecmp (hdr + 1, "ontent-type: text/html", 22) == 0) cpriv->state = P_HTML; break; case 'l': if (line->iov_len > 10 && strncasecmp (hdr + 1, "ocation: ", 9) == 0) fetch_uri (sess, priv, cpriv, hdr + 10, line->iov_len - 10); break; } }
static void call_issue (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg) { Call_Private_Data *cpriv; Sess_Private_Data *priv; Sess *sess; Call *call; assert (et == EV_CALL_ISSUE && object_is_call (obj)); call = (Call *) obj; cpriv = CALL_PRIVATE_DATA (call); if (cpriv->cookie_present) /* don't do anything if cookie has been set already */ return; sess = session_get_sess_from_call (call); priv = SESS_PRIVATE_DATA (sess); if (priv->cookie_len > 0) { if (DBG > 1) fprintf (stderr, "call_issue.%ld: inserting `%s'\n", call->id, priv->cookie); cpriv->cookie_present = 1; memcpy (cpriv->cookie, priv->cookie, priv->cookie_len + 1); call_append_request_header (call, cpriv->cookie, priv->cookie_len); } }
int session_issue_call (Sess *sess, Call *call) { Call_Private_Data *cpriv; Sess_Private_Data *priv; struct Conn_Info *ci; int i; priv = SESS_PRIVATE_DATA (sess); cpriv = CALL_PRIVATE_DATA (call); cpriv->sess = sess; for (i = 0; i < param.max_conns; ++i) { ci = priv->conn_info + i; if (ci->num_pending < param.max_piped) { ++ci->num_pending; ci->call[ci->wr] = call; call_inc_ref (call); ci->wr = (ci->wr + 1) % MAX_PIPED; send_calls (sess, ci); return 0; } } fprintf (stderr, "%s.session_issue_call: too many calls pending!\n" "\tIncrease --max-connections and/or --max-piped-calls.\n", prog_name); exit (1); }
static void flush_print_buf (Call *call, const char *prefix) { Call_Private_Data *priv = CALL_PRIVATE_DATA (call); if (priv->len) printf ("%s%ld:%.*s\n", prefix, call->id, (int) priv->len, priv->line); priv->len = 0; }
static void call_destroyed (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg) { Call_Private_Data *priv; Call *call; assert (et == EV_CALL_DESTROYED && object_is_call (obj)); call = (Call *) obj; priv = CALL_PRIVATE_DATA (call); if (priv->line) free (priv->line); }
static void print_buf (Call *call, const char *prefix, const char *buf, int len) { Call_Private_Data *priv = CALL_PRIVATE_DATA (call); const char *eol, *end; size_t line_len; for (end = buf + len; buf < end; buf += line_len) { line_len = (end - buf); eol = strchr (buf, '\n'); if (eol) { /* got a complete line: print it */ line_len = eol - buf; printf ("%s%ld:", prefix, call->id); if (priv->len) printf ("%.*s", (int) priv->len, priv->line); priv->len = 0; if (line_len > 0) printf ("%.*s", (int) line_len, buf); putchar ('\n'); ++line_len; /* skip over newline */ } else { /* got a partial line: buffer it */ if (priv->len + line_len > priv->size) { priv->size = priv->len + line_len; if (priv->line) priv->line = realloc (priv->line, priv->size); else priv->line = malloc (priv->size); if (!priv->line) { fprintf (stderr, "%s.print_buf: Out of memory\n", prog_name); exit (1); } } memcpy (priv->line + priv->len, buf, line_len); priv->len += line_len; } } }
static void issue_calls (Sess *sess, Sess_Private_Data *priv) { int i, to_create, retval, embedded = 0; Call_Private_Data *cpriv; struct uri_list *el; Call *call; /* Mimic browser behavior of fetching html object, then a couple of embedded objects: */ to_create = 1; if (priv->num_created > 0) { to_create = session_max_qlen (sess) - session_current_qlen (sess); embedded = 1; } for (i = 0; i < to_create && (!embedded || priv->uri_list); ++i) { ++priv->num_created; call = call_new (); if (!call) { sess_failure (sess); return; } if (embedded) { el = priv->uri_list; priv->uri_list = el->next; cpriv = CALL_PRIVATE_DATA (call); cpriv->to_free = el; call_set_uri (call, el->uri, el->uri_len); } if (verbose > 1) printf ("%s: fetching `%s'\n", prog_name, (char *)call->req.iov[IE_URI].iov_base); retval = session_issue_call (sess, call); call_dec_ref (call); if (retval < 0) return; } }
static void call_destroyed (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg) { Call_Private_Data *cpriv; Sess_Private_Data *priv; Any_Type arg; Sess *sess; Call *call; assert (et == EV_CALL_DESTROYED && object_is_call (obj)); call = (Call *) obj; cpriv = CALL_PRIVATE_DATA (call); sess = session_get_sess_from_call (call); priv = SESS_PRIVATE_DATA (sess); if (cpriv->to_free) { free (cpriv->to_free); cpriv->to_free = 0; } ++priv->num_destroyed; if (sess->failed) return; if (priv->uri_list) /* there are some queued URI's which we may be able to issue now */ issue_calls (sess, priv); else if (priv->num_destroyed >= priv->num_created) { /* we're done with this burst */ if (++priv->num_reqs_completed >= param.wsesspage.num_reqs) /* we're done with this session */ sess_dec_ref (sess); else { /* schedule the user-think-time timer */ priv->num_created = 0; assert (!priv->timer); arg.vp = sess; priv->timer = timer_schedule (user_think_time_expired, arg, param.wsesspage.think_time); } } }
static void call_recv_data (Event_Type et, Object *obj, Any_Type regarg, Any_Type callarg) { Call_Private_Data *cpriv; Sess_Private_Data *priv; const char *cp, *end; struct iovec *line; Sess *sess; Call *call; int ch; assert (et == EV_CALL_RECV_DATA && object_is_call (obj)); call = (Call *) obj; cpriv = CALL_PRIVATE_DATA (call); sess = session_get_sess_from_call (call); priv = SESS_PRIVATE_DATA (sess); if (cpriv->state == P_INITIAL) return; /* not an html object */ line = callarg.vp; cp = line->iov_base; end = cp + line->iov_len; while (cp < end) { ch = *cp++; switch (cpriv->state) { case P_INITIAL: break; case P_HTML: cpriv->buf_len = 0; if (ch == '<') cpriv->state = P_CMD; break; case P_CMD: if (isspace (ch) || ch == '=') { if (cpriv->buf_len > 0) { if (DBG > 3) fprintf (stderr, "found command `%.*s'\n", cpriv->buf_len, cpriv->buf); if (cpriv->buf_len == 3 && strcmp (cpriv->buf, "!--") == 0) cpriv->state = P_DASH_ONE; else if (cpriv->buf_len == 5 && strncasecmp (cpriv->buf, "frame", 5) == 0) cpriv->state = P_SRC; else if (cpriv->buf_len == 6 && strncasecmp (cpriv->buf, "iframe", 6) == 0) cpriv->state = P_SRC; else if (cpriv->buf_len == 6 && strncasecmp (cpriv->buf, "data", 6) == 0) cpriv->state = P_DATA; else if (cpriv->buf_len == 3 && strncasecmp (cpriv->buf, "img", 3) == 0) cpriv->state = P_SRC; cpriv->buf_len = 0; } else cpriv->state = P_HTML; } else if (ch == '>') cpriv->state = P_HTML; else if (cpriv->buf_len < sizeof (cpriv->buf)) cpriv->buf[cpriv->buf_len++] = ch; break; case P_DASH_ONE: if (ch == '-') cpriv->state = P_DASH_TWO; break; case P_DASH_TWO: cpriv->state = (ch == '-') ? P_RANGLE : P_DASH_ONE; break; case P_RANGLE: if (ch == '>') cpriv->state = P_HTML; break; case P_SRC: if (ch == '>') cpriv->state = P_HTML; else { cpriv->buf[cpriv->buf_len++] = ch; if (cpriv->buf_len == 4) { if (strncasecmp (cpriv->buf, "src=", 4) == 0) { cpriv->state = P_LQUOTE; cpriv->buf_len = 0; } else { memcpy (cpriv->buf, cpriv->buf + 1, 3); cpriv->buf_len = 3; } } } break; case P_DATA: if (ch == '>') cpriv->state = P_HTML; else { cpriv->buf[cpriv->buf_len++] = ch; if (cpriv->buf_len == 5) { if (strncasecmp (cpriv->buf, "data=", 5) == 0) { cpriv->state = P_LQUOTE; cpriv->buf_len = 0; } else { memcpy (cpriv->buf, cpriv->buf + 1, 4); cpriv->buf_len = 4; } } } break; case P_LQUOTE: if (ch == '"') cpriv->state = P_QUOTED_URI; else if (!isspace (ch)) { cpriv->state = P_NAKED_URI; cpriv->buf[cpriv->buf_len++] = ch; } break; case P_NAKED_URI: case P_QUOTED_URI: if ((cpriv->state == P_QUOTED_URI && ch == '"') || (cpriv->state == P_NAKED_URI && isspace (ch))) { cpriv->buf[cpriv->buf_len] = '\0'; fetch_uri (sess, priv, cpriv, cpriv->buf, cpriv->buf_len); cpriv->state = P_HTML; cpriv->buf_len = 0; } else if (cpriv->buf_len < sizeof (cpriv->buf) - 1) cpriv->buf[cpriv->buf_len++] = ch; break; } } }
Sess * session_get_sess_from_call (Call *call) { assert (object_is_call (call)); return CALL_PRIVATE_DATA (call)->sess; }