Files
scylladb/http/request_parser.rl
2015-03-30 15:38:41 +03:00

140 lines
3.1 KiB
Ragel

/*
* This file is open source software, licensed to you under the terms
* of the Apache License, Version 2.0 (the "License"). See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* Copyright (C) 2014 Cloudius Systems, Ltd.
*/
#pragma once
#include "core/ragel.hh"
#include <memory>
#include <unordered_map>
#include "http/request.hh"
using namespace httpd;
%% machine request;
%%{
access _fsm_;
action mark {
g.mark_start(p);
}
action store_method {
_req->_method = str();
}
action store_uri {
_req->_url = str();
}
action store_version {
_req->_version = str();
}
action store_field_name {
_field_name = str();
}
action store_value {
_value = str();
}
action assign_field {
_req->_headers[_field_name] = std::move(_value);
}
action extend_field {
_req->_headers[_field_name] += sstring(" ") + std::move(_value);
}
action done {
done = true;
fbreak;
}
crlf = '\r\n';
tchar = alpha | digit | '-' | '!' | '#' | '$' | '%' | '&' | '\'' | '*'
| '+' | '.' | '^' | '_' | '`' | '|' | '~';
sp = ' ';
ht = '\t';
sp_ht = sp | ht;
op_char = upper;
operation = op_char+ >mark %store_method;
uri = (any - sp)+ >mark %store_uri;
http_version = 'HTTP/' (digit '.' digit) >mark %store_version;
field = tchar+ >mark %store_field_name;
value = any* >mark %store_value;
start_line = ((operation sp uri sp http_version) -- crlf) crlf;
header_1st = (field sp_ht* ':' 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_request_parser : public ragel_parser_base<http_request_parser> {
%% write data nofinal noprefix;
public:
enum class state {
error,
eof,
done,
};
std::unique_ptr<httpd::request> _req;
sstring _field_name;
sstring _value;
state _state;
public:
void init() {
init_base();
_req.reset(new httpd::request());
_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_request() {
return std::move(_req);
}
bool eof() const {
return _state == state::eof;
}
};