357 lines
10 KiB
Ragel
Executable File
357 lines
10 KiB
Ragel
Executable File
/*
|
|
* Copyright (C) 2009-2015 Mamadou DIOP.
|
|
*
|
|
* This file is part of Open Source Doubango Framework.
|
|
*
|
|
* DOUBANGO is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* DOUBANGO is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with DOUBANGO.
|
|
*
|
|
*/
|
|
/**@file tmsrp_machine_message.rl
|
|
* @brief Ragel file.
|
|
*/
|
|
#include "tinymsrp/parsers/tmsrp_parser_message.h"
|
|
|
|
#include "tinymsrp/headers/tmsrp_header_Dummy.h"
|
|
#include "tinymsrp/headers/tmsrp_header_Expires.h"
|
|
#include "tinymsrp/headers/tmsrp_header_Max-Expires.h"
|
|
#include "tinymsrp/headers/tmsrp_header_Min-Expires.h"
|
|
#include "tinymsrp/headers/tmsrp_header_Use-Path.h"
|
|
#include "tinymsrp/headers/tmsrp_header_WWW-Authenticate.h"
|
|
|
|
#include "tsk_string.h"
|
|
#include "tsk_memory.h"
|
|
#include "tsk_debug.h"
|
|
|
|
static tsk_bool_t parse_payload(tmsrp_message_t* msrp_msg, const char* tag_start, const char** p, const char* pe, tsk_bool_t* payload_parsed);
|
|
static void set_payload(tmsrp_message_t* msrp_msg, const void* ptr, tsk_size_t len);
|
|
|
|
#define TMSRP_MSG_PARSER_ADD_HEADER(name) \
|
|
if((header = (tmsrp_header_t*)tmsrp_header_##name##_parse(tag_start, (p - tag_start)))){ \
|
|
tmsrp_message_add_header(msrp_msg, header); \
|
|
header = tsk_object_unref(header); \
|
|
}
|
|
%%{
|
|
machine tmsrp_machine_message;
|
|
|
|
###########################################
|
|
# Includes
|
|
###########################################
|
|
include tmsrp_machine_utils "./ragel/tmsrp_machine_utils.rl";
|
|
|
|
action tag{
|
|
tag_start = p;
|
|
}
|
|
|
|
###########################################
|
|
# Actions
|
|
###########################################
|
|
action parse_Authentication_Info{
|
|
//FIXME: TMSRP_MSG_PARSER_ADD_HEADER(Authentication_Info);
|
|
TSK_DEBUG_WARN("Authentication_Info Not implemented");
|
|
}
|
|
|
|
action parse_Authorization{
|
|
//FIXME: TMSRP_MSG_PARSER_ADD_HEADER(Authorization);
|
|
TSK_DEBUG_WARN("Authorization Not implemented");
|
|
}
|
|
|
|
action parse_Byte_Range{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(Byte_Range);
|
|
}
|
|
|
|
action parse_Content_Type{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(Content_Type);
|
|
}
|
|
|
|
action parse_Expires{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(Expires);
|
|
}
|
|
|
|
action parse_Failure_Report{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(Failure_Report);
|
|
}
|
|
|
|
action parse_From_Path{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(From_Path);
|
|
}
|
|
|
|
action parse_Max_Expires{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(Max_Expires);
|
|
}
|
|
|
|
action parse_Message_ID{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(Message_ID);
|
|
}
|
|
|
|
action parse_Min_Expires{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(Min_Expires);
|
|
}
|
|
|
|
action parse_Status{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(Status);
|
|
}
|
|
|
|
action parse_Success_Report{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(Success_Report);
|
|
}
|
|
|
|
action parse_To_Path{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(To_Path);
|
|
}
|
|
|
|
action parse_Use_Path{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(Use_Path);
|
|
}
|
|
|
|
action parse_WWW_Authenticate{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(WWW_Authenticate);
|
|
}
|
|
|
|
action parse_Dummy{
|
|
TMSRP_MSG_PARSER_ADD_HEADER(Dummy);
|
|
}
|
|
|
|
action parse_tid{
|
|
TSK_PARSER_SET_STRING(msrp_msg->tid);
|
|
}
|
|
|
|
action parse_method{
|
|
if(msrp_msg->type == tmsrp_unknown){
|
|
msrp_msg->type = tmsrp_request;
|
|
TSK_PARSER_SET_STRING(msrp_msg->line.request.method);
|
|
msrp_msg->line.request.type = tmsrp_request_get_type(msrp_msg->line.request.method);
|
|
}
|
|
else{
|
|
//cs = %%{ write first_final; }%%;
|
|
cs = tmsrp_machine_message_error;
|
|
TSK_DEBUG_ERROR("Message type already defined.");
|
|
}
|
|
}
|
|
|
|
|
|
action parse_status_code{
|
|
if(msrp_msg->type == tmsrp_unknown){
|
|
msrp_msg->type = tmsrp_response;
|
|
TSK_PARSER_SET_INT(msrp_msg->line.response.status);
|
|
}
|
|
else{
|
|
//cs = %%{ write first_final; }%%;
|
|
cs = tmsrp_machine_message_error;
|
|
TSK_DEBUG_ERROR("Message type already defined.");
|
|
}
|
|
}
|
|
action parse_comment{
|
|
TSK_PARSER_SET_STRING(msrp_msg->line.response.comment);
|
|
}
|
|
|
|
|
|
action try_parse_data{
|
|
parse_payload(msrp_msg, tag_start, &p, pe, &payload_parsed); // will update "p"
|
|
}
|
|
|
|
action parse_data{
|
|
// if the msrp message contain a valid content-type, then gob it otherwise continue until we reach the endline
|
|
int len;
|
|
if(parse_payload(msrp_msg, tag_start, &p, pe, &payload_parsed)){ // will update "p"
|
|
// (This space left deliberately blank)
|
|
}
|
|
else if((len = (int)(p - tag_start))>0){
|
|
set_payload(msrp_msg, tag_start, (tsk_size_t)len);
|
|
}
|
|
}
|
|
|
|
action parse_endtid{
|
|
TSK_PARSER_SET_STRING(msrp_msg->end_line.tid);
|
|
}
|
|
|
|
action parse_cflag{
|
|
if(tag_start){
|
|
msrp_msg->end_line.cflag = *tag_start;
|
|
}
|
|
else msrp_msg->end_line.cflag = '#';
|
|
}
|
|
|
|
action outside_endline{
|
|
*msg_size = (p - (const char*)input) + 1;
|
|
}
|
|
|
|
action into_endline{
|
|
into_endline = tsk_true;
|
|
}
|
|
action endtid_match{
|
|
( into_endline || (((pe-p) >7/*seven hyphens*/) && (msrp_msg->tid) && tsk_strniequals(msrp_msg->tid, (p+7), tsk_strlen(msrp_msg->tid))) )
|
|
}
|
|
|
|
|
|
###########################################
|
|
# Headers
|
|
###########################################
|
|
|
|
Authentication_Info = "Authentication-Info:"i SP any* :>CRLF %parse_Authentication_Info;
|
|
Authorization = "Authorization:"i SP any* :>CRLF %parse_Authorization;
|
|
Byte_Range = "Byte-Range:"i SP any* :>CRLF %parse_Byte_Range;
|
|
Content_Type = "Content-Type:"i SP any* :>CRLF %parse_Content_Type;
|
|
Expires = "Expires:"i SP any* :>CRLF %parse_Expires;
|
|
Failure_Report = "Failure-Report:"i SP any* :>CRLF %parse_Failure_Report ;
|
|
From_Path = "From-Path:"i SP any* :>CRLF %parse_From_Path ;
|
|
Max_Expires = "Max-Expires:"i SP any* :>CRLF %parse_Max_Expires;
|
|
Message_ID = "Message-ID:"i SP any* :>CRLF %parse_Message_ID;
|
|
Min_Expires = "Min-Expires:"i SP any* :>CRLF %parse_Min_Expires;
|
|
Status = "Status:"i SP any* :>CRLF %parse_Status;
|
|
Success_Report = "Success-Report:"i SP any* :>CRLF %parse_Success_Report;
|
|
To_Path = "To-Path:"i SP any* :>CRLF %parse_To_Path;
|
|
Use_Path = "Use-Path:"i SP any* :>CRLF %parse_Use_Path;
|
|
WWW_Authenticate = "WWW-Authenticate:"i SP any* :>CRLF %parse_WWW_Authenticate;
|
|
|
|
Dummy = hname ":" SP hval :>CRLF %parse_Dummy;
|
|
|
|
header = (Authentication_Info | Authorization | Byte_Range | Content_Type | Expires | Failure_Report | From_Path | Max_Expires | Message_ID | Min_Expires | Status | Success_Report | To_Path | Use_Path | WWW_Authenticate)>tag @10 | (Dummy>tag) @0;
|
|
|
|
#headers = To_Path From_Path ( header )*;
|
|
headers = ( header )*;
|
|
|
|
###########################################
|
|
# Utils
|
|
###########################################
|
|
transact_id = ident;
|
|
method = UPALPHA*;
|
|
status_code = DIGIT{3};
|
|
comment = utf8text;
|
|
|
|
continuation_flag = "+" | "$" | "#";
|
|
end_line = "-------" transact_id>tag %parse_endtid continuation_flag>tag %parse_cflag CRLF;
|
|
|
|
Other_Mime_header = Dummy;
|
|
|
|
data = any*;
|
|
|
|
###########################################
|
|
# Request
|
|
###########################################
|
|
req_start = "MSRP" SP transact_id>tag %parse_tid SP method>tag %parse_method CRLF;
|
|
#content_stuff = (Other_Mime_header)* CRLF data>tag %parse_data :>CRLF;
|
|
content_stuff = data>tag >try_parse_data %parse_data;
|
|
msrp_request = req_start headers>10 (CRLF content_stuff CRLF)?>5 :>end_line when endtid_match >into_endline;
|
|
|
|
###########################################
|
|
# Response
|
|
###########################################
|
|
resp_start = "MSRP" SP transact_id>tag %parse_tid SP status_code>tag %parse_status_code (SP comment>tag %parse_comment)? CRLF;
|
|
msrp_response = resp_start headers end_line;
|
|
|
|
###########################################
|
|
# Message
|
|
###########################################
|
|
msrp_req_or_resp = (msrp_request | msrp_response)>1 @outside_endline any*>0;
|
|
|
|
###########################################
|
|
# Entry Point
|
|
###########################################
|
|
main := msrp_req_or_resp;
|
|
}%%
|
|
|
|
TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
|
|
/* Ragel data */
|
|
%% write data;
|
|
TSK_RAGEL_DISABLE_WARNINGS_END()
|
|
|
|
tmsrp_message_t* tmsrp_message_parse(const void *input, tsk_size_t size)
|
|
{
|
|
tsk_size_t msg_size;
|
|
return tmsrp_message_parse_2(input, size, &msg_size);
|
|
}
|
|
|
|
tmsrp_message_t* tmsrp_message_parse_2(const void *input, tsk_size_t size, tsk_size_t* msg_size)
|
|
{
|
|
tmsrp_message_t* msrp_msg = tsk_null;
|
|
const char* tag_start = tsk_null;
|
|
tmsrp_header_t* header = tsk_null;
|
|
tsk_bool_t into_endline = tsk_false;
|
|
tsk_bool_t payload_parsed = tsk_false;
|
|
|
|
/* Ragel variables */
|
|
int cs = 0;
|
|
const char* p = input;
|
|
const char* pe = p + size;
|
|
const char* eof = tsk_null;
|
|
|
|
(void)(eof);
|
|
(void)(tmsrp_machine_message_first_final);
|
|
(void)(tmsrp_machine_message_error);
|
|
(void)(tmsrp_machine_message_en_main);
|
|
|
|
*msg_size = 0;
|
|
|
|
if(!input || !size){
|
|
//TSK_DEBUG_ERROR("Null or empty buffer."); // --> very common case(stream): do not bother us...
|
|
goto bail;
|
|
}
|
|
|
|
if(!(msrp_msg = tmsrp_message_create_null())){
|
|
goto bail;
|
|
}
|
|
|
|
TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
|
|
/* Ragel init */
|
|
%% write init;
|
|
|
|
/* Ragel execute */
|
|
%% write exec;
|
|
TSK_RAGEL_DISABLE_WARNINGS_END()
|
|
|
|
/* Check result */
|
|
if( cs < %%{ write first_final; }%% ){
|
|
//TSK_DEBUG_ERROR("Failed to parse MSRP message."); --> very common case(stream): do not bother us...
|
|
TSK_OBJECT_SAFE_FREE(msrp_msg);
|
|
goto bail;
|
|
}
|
|
|
|
bail:
|
|
return msrp_msg;
|
|
}
|
|
|
|
static tsk_bool_t parse_payload(tmsrp_message_t* msrp_msg, const char* tag_start, const char** p, const char* pe, tsk_bool_t* payload_parsed)
|
|
{
|
|
int64_t payload_len, endline_len;
|
|
tsk_bool_t can_parse_payload;
|
|
|
|
if(*payload_parsed){
|
|
TSK_DEBUG_INFO("payload already parsed");
|
|
return tsk_true;
|
|
}
|
|
|
|
if(pe && p && *p && msrp_msg && (can_parse_payload = TMSRP_HEADER_BYTE_RANGE_IS_VALID(msrp_msg->ByteRange))){
|
|
payload_len = (msrp_msg->ByteRange->end - msrp_msg->ByteRange->start) + 1;
|
|
endline_len = 2/*CRLF*/ + 7/*hyphens*/ + tsk_strlen(msrp_msg->tid) + 2/*CRLF*/;
|
|
can_parse_payload = (pe - tag_start) > (payload_len + endline_len);
|
|
if(can_parse_payload){
|
|
set_payload(msrp_msg, tag_start, (tsk_size_t)payload_len);
|
|
*p = ((tag_start + payload_len) - 1);
|
|
*payload_parsed = tsk_true;
|
|
return tsk_true;
|
|
}
|
|
}
|
|
return tsk_false;
|
|
}
|
|
|
|
static void set_payload(tmsrp_message_t* msrp_msg, const void* ptr, tsk_size_t len)
|
|
{
|
|
if(msrp_msg->Content){
|
|
tsk_buffer_cleanup(msrp_msg->Content);
|
|
tsk_buffer_append(msrp_msg->Content, ptr, len);
|
|
}
|
|
else{
|
|
msrp_msg->Content = tsk_buffer_create(ptr, len);
|
|
}
|
|
} |