doubango/tinyMSRP/ragel/tmsrp_parser_message.rl

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