Merge tag 'weighttp-0.3' into debian
weighttp v0.3
This commit is contained in:
commit
e7dbbd757f
2
COPYING
2
COPYING
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
|
|
||||||
Copyright (c) 2009 Thomas Porzelt
|
Copyright (c) 2009-2011 Thomas Porzelt
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
51
src/client.c
51
src/client.c
@ -2,7 +2,7 @@
|
|||||||
* weighttp - a lightweight and simple webserver benchmarking tool
|
* weighttp - a lightweight and simple webserver benchmarking tool
|
||||||
*
|
*
|
||||||
* Author:
|
* Author:
|
||||||
* Copyright (c) 2009 Thomas Porzelt
|
* Copyright (c) 2009-2011 Thomas Porzelt
|
||||||
*
|
*
|
||||||
* License:
|
* License:
|
||||||
* MIT, see COPYING file
|
* MIT, see COPYING file
|
||||||
@ -106,7 +106,7 @@ static void client_reset(Client *client) {
|
|||||||
client->request_offset = 0;
|
client->request_offset = 0;
|
||||||
client->ts_start = 0;
|
client->ts_start = 0;
|
||||||
client->ts_end = 0;
|
client->ts_end = 0;
|
||||||
client->status_200 = 0;
|
client->status_success = 0;
|
||||||
client->success = 0;
|
client->success = 0;
|
||||||
client->content_length = -1;
|
client->content_length = -1;
|
||||||
client->bytes_received = 0;
|
client->bytes_received = 0;
|
||||||
@ -259,7 +259,7 @@ void client_state_machine(Client *client) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* disconnect */
|
/* disconnect */
|
||||||
if (client->parser_state == PARSER_BODY && !client->keepalive && client->status_200
|
if (client->parser_state == PARSER_BODY && !client->keepalive && client->status_success
|
||||||
&& !client->chunked && client->content_length == -1) {
|
&& !client->chunked && client->content_length == -1) {
|
||||||
client->success = 1;
|
client->success = 1;
|
||||||
client->state = CLIENT_END;
|
client->state = CLIENT_END;
|
||||||
@ -314,27 +314,50 @@ void client_state_machine(Client *client) {
|
|||||||
|
|
||||||
static uint8_t client_parse(Client *client, int size) {
|
static uint8_t client_parse(Client *client, int size) {
|
||||||
char *end, *str;
|
char *end, *str;
|
||||||
|
uint16_t status_code;
|
||||||
|
|
||||||
switch (client->parser_state) {
|
switch (client->parser_state) {
|
||||||
case PARSER_START:
|
case PARSER_START:
|
||||||
//printf("parse (START):\n%s\n", &client->buffer[client->parser_offset]);
|
//printf("parse (START):\n%s\n", &client->buffer[client->parser_offset]);
|
||||||
/* look for HTTP/1.1 200 OK */
|
/* look for HTTP/1.1 200 OK */
|
||||||
if (client->buffer_offset < sizeof("HTTP/1.1 200 OK\r\n"))
|
if (client->buffer_offset < sizeof("HTTP/1.1 200\r\n"))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (strncmp(client->buffer, "HTTP/1.1 200 OK\r\n", sizeof("HTTP/1.1 200 OK\r\n")-1) == 0) {
|
if (strncmp(client->buffer, "HTTP/1.1 ", sizeof("HTTP/1.1 ")-1) != 0)
|
||||||
client->status_200 = 1;
|
return 0;
|
||||||
client->parser_offset = sizeof("HTTP/1.1 200 ok\r\n") - 1;
|
|
||||||
} else {
|
|
||||||
client->status_200 = 0;
|
|
||||||
end = strchr(client->buffer, '\r');
|
|
||||||
|
|
||||||
if (!end || *(end+1) != '\n')
|
// now the status code
|
||||||
|
status_code = 0;
|
||||||
|
str = client->buffer + sizeof("HTTP/1.1 ")-1;
|
||||||
|
for (end = str + 3; str != end; str++) {
|
||||||
|
if (*str < '0' || *str > '9')
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
client->parser_offset = end + 2 - client->buffer;
|
status_code *= 10;
|
||||||
|
status_code += *str - '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status_code >= 200 && status_code < 300) {
|
||||||
|
client->worker->stats.req_2xx++;
|
||||||
|
client->status_success = 1;
|
||||||
|
} else if (status_code < 400) {
|
||||||
|
client->worker->stats.req_3xx++;
|
||||||
|
client->status_success = 1;
|
||||||
|
} else if (status_code < 500) {
|
||||||
|
client->worker->stats.req_4xx++;
|
||||||
|
} else if (status_code < 600) {
|
||||||
|
client->worker->stats.req_5xx++;
|
||||||
|
} else {
|
||||||
|
// invalid status code
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for next \r\n
|
||||||
|
end = strchr(end, '\r');
|
||||||
|
if (!end || *(end+1) != '\n')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
client->parser_offset = end + 2 - client->buffer;
|
||||||
client->parser_state = PARSER_HEADER;
|
client->parser_state = PARSER_HEADER;
|
||||||
case PARSER_HEADER:
|
case PARSER_HEADER:
|
||||||
//printf("parse (HEADER)\n");
|
//printf("parse (HEADER)\n");
|
||||||
@ -441,7 +464,7 @@ static uint8_t client_parse(Client *client, int size) {
|
|||||||
if (client->chunk_size == 0) {
|
if (client->chunk_size == 0) {
|
||||||
/* chunk of size 0 marks end of content body */
|
/* chunk of size 0 marks end of content body */
|
||||||
client->state = CLIENT_END;
|
client->state = CLIENT_END;
|
||||||
client->success = client->status_200 ? 1 : 0;
|
client->success = client->status_success ? 1 : 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,7 +513,7 @@ static uint8_t client_parse(Client *client, int size) {
|
|||||||
if (client->bytes_received == (uint64_t) (client->header_size + client->content_length)) {
|
if (client->bytes_received == (uint64_t) (client->header_size + client->content_length)) {
|
||||||
/* full response received */
|
/* full response received */
|
||||||
client->state = CLIENT_END;
|
client->state = CLIENT_END;
|
||||||
client->success = client->status_200 ? 1 : 0;
|
client->success = client->status_success ? 1 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* weighttp - a lightweight and simple webserver benchmarking tool
|
* weighttp - a lightweight and simple webserver benchmarking tool
|
||||||
*
|
*
|
||||||
* Author:
|
* Author:
|
||||||
* Copyright (c) 2009 Thomas Porzelt
|
* Copyright (c) 2009-2011 Thomas Porzelt
|
||||||
*
|
*
|
||||||
* License:
|
* License:
|
||||||
* MIT, see COPYING file
|
* MIT, see COPYING file
|
||||||
@ -33,7 +33,7 @@ struct Client {
|
|||||||
ev_tstamp ts_end;
|
ev_tstamp ts_end;
|
||||||
uint8_t keepalive;
|
uint8_t keepalive;
|
||||||
uint8_t success;
|
uint8_t success;
|
||||||
uint8_t status_200;
|
uint8_t status_success;
|
||||||
uint8_t chunked;
|
uint8_t chunked;
|
||||||
int64_t chunk_size;
|
int64_t chunk_size;
|
||||||
int64_t chunk_received;
|
int64_t chunk_received;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* weighttp - a lightweight and simple webserver benchmarking tool
|
* weighttp - a lightweight and simple webserver benchmarking tool
|
||||||
*
|
*
|
||||||
* Author:
|
* Author:
|
||||||
* Copyright (c) 2009 Thomas Porzelt
|
* Copyright (c) 2009-2011 Thomas Porzelt
|
||||||
*
|
*
|
||||||
* License:
|
* License:
|
||||||
* MIT, see COPYING file
|
* MIT, see COPYING file
|
||||||
@ -19,8 +19,10 @@ static void show_help(void) {
|
|||||||
printf(" -c num concurrent clients (default: 1)\n");
|
printf(" -c num concurrent clients (default: 1)\n");
|
||||||
printf(" -k keep alive (default: no)\n");
|
printf(" -k keep alive (default: no)\n");
|
||||||
printf(" -6 use ipv6 (default: no)\n");
|
printf(" -6 use ipv6 (default: no)\n");
|
||||||
|
printf(" -H str add header to request\n");
|
||||||
printf(" -h show help and exit\n");
|
printf(" -h show help and exit\n");
|
||||||
printf(" -v show version and exit\n\n");
|
printf(" -v show version and exit\n\n");
|
||||||
|
printf("example: weighttpd -n 10000 -c 10 -t 2 -k -H \"User-Agent: foo\" localhost/index.html\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct addrinfo *resolve_host(char *hostname, uint16_t port, uint8_t use_ipv6) {
|
static struct addrinfo *resolve_host(char *hostname, uint16_t port, uint8_t use_ipv6) {
|
||||||
@ -68,10 +70,12 @@ static struct addrinfo *resolve_host(char *hostname, uint16_t port, uint8_t use_
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *forge_request(char *url, char keep_alive, char **host, uint16_t *port) {
|
static char *forge_request(char *url, char keep_alive, char **host, uint16_t *port, char **headers, uint8_t headers_num) {
|
||||||
char *c, *end;
|
char *c, *end;
|
||||||
char *req;
|
char *req;
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t have_user_agent;
|
||||||
|
|
||||||
*host = NULL;
|
*host = NULL;
|
||||||
*port = 0;
|
*port = 0;
|
||||||
@ -126,7 +130,22 @@ static char *forge_request(char *url, char keep_alive, char **host, uint16_t *po
|
|||||||
if (*url == '\0')
|
if (*url == '\0')
|
||||||
url = "/";
|
url = "/";
|
||||||
|
|
||||||
req = W_MALLOC(char, sizeof("GET HTTP/1.1\r\nHost: :65536\r\nUser-Agent: weighttp/\r\nConnection: keep-alive\r\n\r\n") + strlen(VERSION) + strlen(*host) + strlen(url));
|
// total request size
|
||||||
|
len = strlen("GET HTTP/1.1\r\nHost: :65536\r\nConnection: keep-alive\r\n\r\n") + 1;
|
||||||
|
len += strlen(*host);
|
||||||
|
len += strlen(url);
|
||||||
|
|
||||||
|
have_user_agent = 0;
|
||||||
|
for (i = 0; i < headers_num; i++) {
|
||||||
|
len += strlen(headers[i]) + strlen("\r\n");
|
||||||
|
if (strncmp(headers[i], "User-Agent: ", sizeof("User-Agent: ")-1) == 0)
|
||||||
|
have_user_agent = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!have_user_agent)
|
||||||
|
len += strlen("User-Agent: weighttp/" VERSION "\r\n");
|
||||||
|
|
||||||
|
req = W_MALLOC(char, len);
|
||||||
|
|
||||||
strcpy(req, "GET ");
|
strcpy(req, "GET ");
|
||||||
strcat(req, url);
|
strcat(req, url);
|
||||||
@ -135,7 +154,15 @@ static char *forge_request(char *url, char keep_alive, char **host, uint16_t *po
|
|||||||
if (*port != 80)
|
if (*port != 80)
|
||||||
sprintf(req + strlen(req), ":%"PRIu16, *port);
|
sprintf(req + strlen(req), ":%"PRIu16, *port);
|
||||||
|
|
||||||
sprintf(req + strlen(req), "\r\nUser-Agent: weighttp/" VERSION "\r\n");
|
strcat(req, "\r\n");
|
||||||
|
|
||||||
|
if (!have_user_agent)
|
||||||
|
sprintf(req + strlen(req), "User-Agent: weighttp/" VERSION "\r\n");
|
||||||
|
|
||||||
|
for (i = 0; i < headers_num; i++) {
|
||||||
|
strcat(req, headers[i]);
|
||||||
|
strcat(req, "\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (keep_alive)
|
if (keep_alive)
|
||||||
strcat(req, "Connection: keep-alive\r\n\r\n");
|
strcat(req, "Connection: keep-alive\r\n\r\n");
|
||||||
@ -178,10 +205,14 @@ int main(int argc, char *argv[]) {
|
|||||||
int sec, millisec, microsec;
|
int sec, millisec, microsec;
|
||||||
uint64_t rps;
|
uint64_t rps;
|
||||||
uint64_t kbps;
|
uint64_t kbps;
|
||||||
|
char **headers;
|
||||||
|
uint8_t headers_num;
|
||||||
|
|
||||||
printf("weighttp - a lightweight and simple webserver benchmarking tool\n\n");
|
printf("weighttp - a lightweight and simple webserver benchmarking tool\n\n");
|
||||||
|
|
||||||
|
headers = NULL;
|
||||||
|
headers_num = 0;
|
||||||
|
|
||||||
/* default settings */
|
/* default settings */
|
||||||
use_ipv6 = 0;
|
use_ipv6 = 0;
|
||||||
config.thread_count = 1;
|
config.thread_count = 1;
|
||||||
@ -189,7 +220,7 @@ int main(int argc, char *argv[]) {
|
|||||||
config.req_count = 0;
|
config.req_count = 0;
|
||||||
config.keep_alive = 0;
|
config.keep_alive = 0;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, ":hv6kn:t:c:")) != -1) {
|
while ((c = getopt(argc, argv, ":hv6kn:t:c:H:")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
show_help();
|
show_help();
|
||||||
@ -213,6 +244,11 @@ int main(int argc, char *argv[]) {
|
|||||||
case 'c':
|
case 'c':
|
||||||
config.concur_count = atoi(optarg);
|
config.concur_count = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'H':
|
||||||
|
headers = W_REALLOC(headers, char*, headers_num+1);
|
||||||
|
headers[headers_num] = optarg;
|
||||||
|
headers_num++;
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
W_ERROR("unkown option: -%c", optopt);
|
W_ERROR("unkown option: -%c", optopt);
|
||||||
show_help();
|
show_help();
|
||||||
@ -259,7 +295,7 @@ int main(int argc, char *argv[]) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL == (config.request = forge_request(argv[optind], config.keep_alive, &host, &port))) {
|
if (NULL == (config.request = forge_request(argv[optind], config.keep_alive, &host, &port, headers, headers_num))) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,6 +369,10 @@ int main(int argc, char *argv[]) {
|
|||||||
stats.req_failed += worker->stats.req_failed;
|
stats.req_failed += worker->stats.req_failed;
|
||||||
stats.bytes_total += worker->stats.bytes_total;
|
stats.bytes_total += worker->stats.bytes_total;
|
||||||
stats.bytes_body += worker->stats.bytes_body;
|
stats.bytes_body += worker->stats.bytes_body;
|
||||||
|
stats.req_2xx += worker->stats.req_2xx;
|
||||||
|
stats.req_3xx += worker->stats.req_3xx;
|
||||||
|
stats.req_4xx += worker->stats.req_4xx;
|
||||||
|
stats.req_5xx += worker->stats.req_5xx;
|
||||||
|
|
||||||
worker_free(worker);
|
worker_free(worker);
|
||||||
}
|
}
|
||||||
@ -351,6 +391,9 @@ int main(int argc, char *argv[]) {
|
|||||||
printf("requests: %"PRIu64" total, %"PRIu64" started, %"PRIu64" done, %"PRIu64" succeeded, %"PRIu64" failed, %"PRIu64" errored\n",
|
printf("requests: %"PRIu64" total, %"PRIu64" started, %"PRIu64" done, %"PRIu64" succeeded, %"PRIu64" failed, %"PRIu64" errored\n",
|
||||||
config.req_count, stats.req_started, stats.req_done, stats.req_success, stats.req_failed, stats.req_error
|
config.req_count, stats.req_started, stats.req_done, stats.req_success, stats.req_failed, stats.req_error
|
||||||
);
|
);
|
||||||
|
printf("status codes: %"PRIu64" 2xx, %"PRIu64" 3xx, %"PRIu64" 4xx, %"PRIu64" 5xx\n",
|
||||||
|
stats.req_2xx, stats.req_3xx, stats.req_4xx, stats.req_5xx
|
||||||
|
);
|
||||||
printf("traffic: %"PRIu64" bytes total, %"PRIu64" bytes http, %"PRIu64" bytes data\n",
|
printf("traffic: %"PRIu64" bytes total, %"PRIu64" bytes http, %"PRIu64" bytes data\n",
|
||||||
stats.bytes_total, stats.bytes_total - stats.bytes_body, stats.bytes_body
|
stats.bytes_total, stats.bytes_total - stats.bytes_body, stats.bytes_body
|
||||||
);
|
);
|
||||||
@ -361,6 +404,7 @@ int main(int argc, char *argv[]) {
|
|||||||
free(workers);
|
free(workers);
|
||||||
free(config.request);
|
free(config.request);
|
||||||
free(host);
|
free(host);
|
||||||
|
free(headers);
|
||||||
freeaddrinfo(config.saddr);
|
freeaddrinfo(config.saddr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* weighttp - a lightweight and simple webserver benchmarking tool
|
* weighttp - a lightweight and simple webserver benchmarking tool
|
||||||
*
|
*
|
||||||
* Author:
|
* Author:
|
||||||
* Copyright (c) 2009 Thomas Porzelt
|
* Copyright (c) 2009-2011 Thomas Porzelt
|
||||||
*
|
*
|
||||||
* License:
|
* License:
|
||||||
* MIT, see COPYING file
|
* MIT, see COPYING file
|
||||||
@ -30,6 +30,7 @@
|
|||||||
#define CLIENT_BUFFER_SIZE 32 * 1024
|
#define CLIENT_BUFFER_SIZE 32 * 1024
|
||||||
|
|
||||||
#define W_MALLOC(t, n) ((t*) calloc((n), sizeof(t)))
|
#define W_MALLOC(t, n) ((t*) calloc((n), sizeof(t)))
|
||||||
|
#define W_REALLOC(p, t, n) ((t*) realloc(p, (n) * sizeof(t)))
|
||||||
#define W_ERROR(f, ...) fprintf(stderr, "error: " f "\n", __VA_ARGS__)
|
#define W_ERROR(f, ...) fprintf(stderr, "error: " f "\n", __VA_ARGS__)
|
||||||
#define UNUSED(x) ( (void)(x) )
|
#define UNUSED(x) ( (void)(x) )
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* weighttp - a lightweight and simple webserver benchmarking tool
|
* weighttp - a lightweight and simple webserver benchmarking tool
|
||||||
*
|
*
|
||||||
* Author:
|
* Author:
|
||||||
* Copyright (c) 2009 Thomas Porzelt
|
* Copyright (c) 2009-2011 Thomas Porzelt
|
||||||
*
|
*
|
||||||
* License:
|
* License:
|
||||||
* MIT, see COPYING file
|
* MIT, see COPYING file
|
||||||
@ -52,7 +52,8 @@ void *worker_thread(void* arg) {
|
|||||||
|
|
||||||
/* start all clients */
|
/* start all clients */
|
||||||
for (i = 0; i < worker->num_clients; i++) {
|
for (i = 0; i < worker->num_clients; i++) {
|
||||||
client_state_machine(worker->clients[i]);
|
if (worker->stats.req_started < worker->stats.req_todo)
|
||||||
|
client_state_machine(worker->clients[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ev_loop(worker->loop, 0);
|
ev_loop(worker->loop, 0);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* weighttp - a lightweight and simple webserver benchmarking tool
|
* weighttp - a lightweight and simple webserver benchmarking tool
|
||||||
*
|
*
|
||||||
* Author:
|
* Author:
|
||||||
* Copyright (c) 2009 Thomas Porzelt
|
* Copyright (c) 2009-2011 Thomas Porzelt
|
||||||
*
|
*
|
||||||
* License:
|
* License:
|
||||||
* MIT, see COPYING file
|
* MIT, see COPYING file
|
||||||
@ -20,6 +20,11 @@ struct Stats {
|
|||||||
uint64_t req_error; /* total number of error'd requests */
|
uint64_t req_error; /* total number of error'd requests */
|
||||||
uint64_t bytes_total; /* total number of bytes received (html+body) */
|
uint64_t bytes_total; /* total number of bytes received (html+body) */
|
||||||
uint64_t bytes_body; /* total number of bytes received (body) */
|
uint64_t bytes_body; /* total number of bytes received (body) */
|
||||||
|
uint64_t req_1xx;
|
||||||
|
uint64_t req_2xx;
|
||||||
|
uint64_t req_3xx;
|
||||||
|
uint64_t req_4xx;
|
||||||
|
uint64_t req_5xx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Worker {
|
struct Worker {
|
||||||
|
4
wscript
4
wscript
@ -5,7 +5,7 @@
|
|||||||
* weighttp - a lightweight and simple webserver benchmarking tool
|
* weighttp - a lightweight and simple webserver benchmarking tool
|
||||||
*
|
*
|
||||||
* Author:
|
* Author:
|
||||||
* Copyright (c) 2009 Thomas Porzelt
|
* Copyright (c) 2009-2011 Thomas Porzelt
|
||||||
*
|
*
|
||||||
* License:
|
* License:
|
||||||
* MIT, see COPYING file
|
* MIT, see COPYING file
|
||||||
@ -14,7 +14,7 @@
|
|||||||
import Options
|
import Options
|
||||||
|
|
||||||
# the following two variables are used by the target "waf dist"
|
# the following two variables are used by the target "waf dist"
|
||||||
VERSION='0.2'
|
VERSION='0.3'
|
||||||
APPNAME='weighttp'
|
APPNAME='weighttp'
|
||||||
|
|
||||||
# these variables are mandatory ('/' are converted automatically)
|
# these variables are mandatory ('/' are converted automatically)
|
||||||
|
Loading…
Reference in New Issue
Block a user