mirror of
https://github.com/scylladb/scylladb.git
synced 2026-04-20 08:30:35 +00:00
It is based on tcp_client and works with our httpd server. 1) timer based, to run the test for 10 seconds $ http_client --server 192.168.66.100:10000 --conn 100 --duration 10 --smp 2 ========== http_client ============ Server: 192.168.66.100:10000 Connections: 100 Requests/connection: dynamic (timer based) Requests on cpu 0: 33400 Requests on cpu 1: 33368 Total cpus: 2 Total requests: 66768 Total time: 10.011478 Requests/sec: 6669.145442 ========== done ============ 2) nr of reqs per connection based, to run the test with 100 connections each has to run 1000 reqs $ http_client --server 192.168.66.100:10000 --conn 100 --reqs 1000 --smp 2 ========== http_client ============ Server: 192.168.66.100:10000 Connections: 100 Requests/connection: 1000 Requests on cpu 0: 50000 Requests on cpu 1: 50000 Total cpus: 2 Total requests: 100000 Total time: 15.002731 Requests/sec: 6665.453192 ========== done ============ This patch is based on Shlomi's initial version. Signed-off-by: Shlomi Livne <shlomi@cloudius-systems.com> Signed-off-by: Asias He <asias@cloudius-systems.com>
113 lines
2.2 KiB
Ragel
113 lines
2.2 KiB
Ragel
/*
|
|
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
|
*/
|
|
|
|
#include "core/ragel.hh"
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
|
|
struct http_response {
|
|
sstring _version;
|
|
std::unordered_map<sstring, sstring> _headers;
|
|
};
|
|
|
|
%% machine http_response;
|
|
|
|
%%{
|
|
|
|
access _fsm_;
|
|
|
|
action mark {
|
|
g.mark_start(p);
|
|
}
|
|
|
|
action store_version {
|
|
_rsp->_version = str();
|
|
}
|
|
|
|
action store_field_name {
|
|
_field_name = str();
|
|
}
|
|
|
|
action store_value {
|
|
_value = str();
|
|
}
|
|
|
|
action assign_field {
|
|
_rsp->_headers[_field_name] = std::move(_value);
|
|
}
|
|
|
|
action extend_field {
|
|
_rsp->_headers[_field_name] += sstring(" ") + std::move(_value);
|
|
}
|
|
|
|
action done {
|
|
done = true;
|
|
fbreak;
|
|
}
|
|
|
|
cr = '\r';
|
|
lf = '\n';
|
|
crlf = '\r\n';
|
|
tchar = alpha | digit | '-' | '!' | '#' | '$' | '%' | '&' | '\'' | '*'
|
|
| '+' | '.' | '^' | '_' | '`' | '|' | '~';
|
|
|
|
sp = ' ';
|
|
ht = '\t';
|
|
|
|
sp_ht = sp | ht;
|
|
|
|
http_version = 'HTTP/' (digit '.' digit) >mark %store_version;
|
|
|
|
field = tchar+ >mark %store_field_name;
|
|
value = any* >mark %store_value;
|
|
start_line = http_version space digit digit digit space (any - cr - lf)* crlf;
|
|
header_1st = (field sp_ht* ':' value :> crlf) %assign_field;
|
|
header_cont = (sp_ht+ value sp_ht* crlf) %extend_field;
|
|
header = header_1st header_cont*;
|
|
main := start_line header* :> (crlf @done);
|
|
|
|
}%%
|
|
|
|
class http_response_parser : public ragel_parser_base<http_response_parser> {
|
|
%% write data nofinal noprefix;
|
|
public:
|
|
enum class state {
|
|
error,
|
|
eof,
|
|
done,
|
|
};
|
|
std::unique_ptr<http_response> _rsp;
|
|
sstring _field_name;
|
|
sstring _value;
|
|
state _state;
|
|
public:
|
|
void init() {
|
|
init_base();
|
|
_rsp.reset(new http_response());
|
|
_state = state::eof;
|
|
%% write init;
|
|
}
|
|
char* parse(char* p, char* pe, char* eof) {
|
|
sstring_builder::guard g(_builder, p, pe);
|
|
auto str = [this, &g, &p] { g.mark_end(p); return get_str(); };
|
|
bool done = false;
|
|
if (p != pe) {
|
|
_state = state::error;
|
|
}
|
|
%% write exec;
|
|
if (!done) {
|
|
p = nullptr;
|
|
} else {
|
|
_state = state::done;
|
|
}
|
|
return p;
|
|
}
|
|
auto get_parsed_response() {
|
|
return std::move(_rsp);
|
|
}
|
|
bool eof() const {
|
|
return _state == state::eof;
|
|
}
|
|
};
|