Files
scylladb/tests/http_response_parser.rl
Asias He 51adb20bda tests: Add http_client
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>
2015-02-12 10:02:48 +02:00

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;
}
};