1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

GB28181: Refine HTTP parser to support SIP. v5.0.70

This commit is contained in:
winlin 2022-09-18 22:50:14 +08:00
parent dae46a59ae
commit 1e6143e2eb
9 changed files with 456 additions and 79 deletions

View file

@ -28,6 +28,7 @@ SrsHttpParser::SrsHttpParser()
p_body_start = p_header_tail = NULL;
type_ = HTTP_REQUEST;
parsed_type_ = HTTP_BOTH;
}
SrsHttpParser::~SrsHttpParser()
@ -70,7 +71,7 @@ srs_error_t SrsHttpParser::parse_message(ISrsReader* reader, ISrsHttpMessage** p
*ppmsg = NULL;
// Reset request data.
// Reset parser data and state.
state = SrsHttpParseStateInit;
memset(&hp_header, 0, sizeof(http_parser));
// The body that we have read from cache.
@ -93,6 +94,8 @@ srs_error_t SrsHttpParser::parse_message(ISrsReader* reader, ISrsHttpMessage** p
// and the message fail.
// @note You can comment the bellow line, the utest will fail.
http_parser_init(&parser, type_);
// Reset the parsed type.
parsed_type_ = HTTP_BOTH;
// callback object ptr.
parser.data = (void*)this;
@ -105,10 +108,10 @@ srs_error_t SrsHttpParser::parse_message(ISrsReader* reader, ISrsHttpMessage** p
SrsHttpMessage* msg = new SrsHttpMessage(reader, buffer);
// Initialize the basic information.
msg->set_basic(hp_header.type, hp_header.method, hp_header.status_code, hp_header.content_length);
msg->set_basic(hp_header.type, (http_method)hp_header.method, (http_status)hp_header.status_code, hp_header.content_length);
msg->set_header(header, http_should_keep_alive(&hp_header));
// For HTTP response, no url.
if (type_ != HTTP_RESPONSE && (err = msg->set_url(url, jsonp)) != srs_success) {
if (parsed_type_ != HTTP_RESPONSE && (err = msg->set_url(url, jsonp)) != srs_success) {
srs_freep(msg);
return srs_error_wrap(err, "set url=%s, jsonp=%d", url.c_str(), jsonp);
}
@ -177,8 +180,12 @@ int SrsHttpParser::on_message_begin(http_parser* parser)
{
SrsHttpParser* obj = (SrsHttpParser*)parser->data;
srs_assert(obj);
// Now, we start to parse HTTP message.
obj->state = SrsHttpParseStateStart;
// If we set to HTTP_BOTH, the type is detected and speicifed by parser.
obj->parsed_type_ = (http_parser_type)parser->type;
srs_info("***MESSAGE BEGIN***");
@ -305,9 +312,9 @@ SrsHttpMessage::SrsHttpMessage(ISrsReader* reader, SrsFastStream* buffer) : ISrs
jsonp = false;
// As 0 is DELETE, so we use GET as default.
_method = SRS_CONSTS_HTTP_GET;
_method = (http_method)SRS_CONSTS_HTTP_GET;
// 200 is ok.
_status = SRS_CONSTS_HTTP_OK;
_status = (http_status)SRS_CONSTS_HTTP_OK;
// -1 means infinity chunked mode.
_content_length = -1;
// From HTTP/1.1, default to keep alive.
@ -323,7 +330,7 @@ SrsHttpMessage::~SrsHttpMessage()
srs_freep(_uri);
}
void SrsHttpMessage::set_basic(uint8_t type, uint8_t method, uint16_t status, int64_t content_length)
void SrsHttpMessage::set_basic(uint8_t type, http_method method, http_status status, int64_t content_length)
{
type_ = type;
_method = method;
@ -376,6 +383,11 @@ srs_error_t SrsHttpMessage::set_url(string url, bool allow_jsonp)
host = srs_get_public_internet_address(true);
}
// The url must starts with slash if no schema. For example, SIP request line starts with "sip".
if (!host.empty() && !srs_string_starts_with(_url, "/")) {
host += "/";
}
if (!host.empty()) {
uri = "http://" + host + _url;
}
@ -425,6 +437,11 @@ string SrsHttpMessage::schema()
return schema_;
}
uint8_t SrsHttpMessage::message_type()
{
return type_;
}
uint8_t SrsHttpMessage::method()
{
if (jsonp && !jsonp_method.empty()) {
@ -654,33 +671,41 @@ ISrsHttpHeaderFilter::~ISrsHttpHeaderFilter()
{
}
SrsHttpResponseWriter::SrsHttpResponseWriter(ISrsProtocolReadWriter* io)
ISrsHttpFirstLineWriter::ISrsHttpFirstLineWriter()
{
}
ISrsHttpFirstLineWriter::~ISrsHttpFirstLineWriter()
{
}
SrsHttpMessageWriter::SrsHttpMessageWriter(ISrsProtocolReadWriter* io, ISrsHttpFirstLineWriter* flw)
{
skt = io;
hdr = new SrsHttpHeader();
header_wrote = false;
status = SRS_CONSTS_HTTP_OK;
header_wrote_ = false;
content_length = -1;
written = 0;
header_sent = false;
nb_iovss_cache = 0;
iovss_cache = NULL;
hf = NULL;
hf_ = NULL;
flw_ = flw;
}
SrsHttpResponseWriter::~SrsHttpResponseWriter()
SrsHttpMessageWriter::~SrsHttpMessageWriter()
{
srs_freep(hdr);
srs_freepa(iovss_cache);
}
srs_error_t SrsHttpResponseWriter::final_request()
srs_error_t SrsHttpMessageWriter::final_request()
{
srs_error_t err = srs_success;
// write the header data in memory.
if (!header_wrote) {
write_header(SRS_CONSTS_HTTP_OK);
if (!header_wrote_) {
flw_->write_default_header();
}
// whatever header is wrote, we should try to send header.
@ -700,24 +725,24 @@ srs_error_t SrsHttpResponseWriter::final_request()
return write(NULL, 0);
}
SrsHttpHeader* SrsHttpResponseWriter::header()
SrsHttpHeader* SrsHttpMessageWriter::header()
{
return hdr;
}
srs_error_t SrsHttpResponseWriter::write(char* data, int size)
srs_error_t SrsHttpMessageWriter::write(char* data, int size)
{
srs_error_t err = srs_success;
// write the header data in memory.
if (!header_wrote) {
if (!header_wrote_) {
if (hdr->content_type().empty()) {
hdr->set_content_type("text/plain; charset=utf-8");
}
if (hdr->content_length() == -1) {
hdr->set_content_length(size);
}
write_header(SRS_CONSTS_HTTP_OK);
flw_->write_default_header();
}
// whatever header is wrote, we should try to send header.
@ -765,12 +790,12 @@ srs_error_t SrsHttpResponseWriter::write(char* data, int size)
return err;
}
srs_error_t SrsHttpResponseWriter::writev(const iovec* iov, int iovcnt, ssize_t* pnwrite)
srs_error_t SrsHttpMessageWriter::writev(const iovec* iov, int iovcnt, ssize_t* pnwrite)
{
srs_error_t err = srs_success;
// when header not ready, or not chunked, send one by one.
if (!header_wrote || content_length != -1) {
if (!header_wrote_ || content_length != -1) {
ssize_t nwrite = 0;
for (int i = 0; i < iovcnt; i++) {
nwrite += iov[i].iov_len;
@ -848,21 +873,16 @@ srs_error_t SrsHttpResponseWriter::writev(const iovec* iov, int iovcnt, ssize_t*
return err;
}
void SrsHttpResponseWriter::write_header(int code)
void SrsHttpMessageWriter::write_header()
{
if (header_wrote) {
srs_warn("http: multiple write_header calls, code=%d", code);
return;
}
header_wrote = true;
status = code;
if (header_wrote_) return;
header_wrote_ = true;
// parse the content length from header.
content_length = hdr->content_length();
}
srs_error_t SrsHttpResponseWriter::send_header(char* data, int size)
srs_error_t SrsHttpMessageWriter::send_header(char* data, int size)
{
srs_error_t err = srs_success;
@ -872,16 +892,10 @@ srs_error_t SrsHttpResponseWriter::send_header(char* data, int size)
header_sent = true;
std::stringstream ss;
// status_line
ss << "HTTP/1.1 " << status << " "
<< srs_generate_http_status_text(status) << SRS_HTTP_CRLF;
// detect content type
if (srs_go_http_body_allowd(status)) {
if (data && hdr->content_type().empty()) {
hdr->set_content_type(srs_go_http_detect(data, size));
}
// First line, the request line or status line.
if ((err = flw_->build_first_line(ss, data, size)) != srs_success) {
return srs_error_wrap(err, "first line");
}
// set server if not set.
@ -900,7 +914,7 @@ srs_error_t SrsHttpResponseWriter::send_header(char* data, int size)
}
// Filter the header before writing it.
if (hf && ((err = hf->filter(hdr)) != srs_success)) {
if (hf_ && ((err = hf_->filter(hdr)) != srs_success)) {
return srs_error_wrap(err, "filter header");
}
@ -914,6 +928,151 @@ srs_error_t SrsHttpResponseWriter::send_header(char* data, int size)
return skt->write((void*)buf.c_str(), buf.length(), NULL);
}
bool SrsHttpMessageWriter::header_wrote()
{
return header_wrote_;
}
void SrsHttpMessageWriter::set_header_filter(ISrsHttpHeaderFilter* hf)
{
hf_ = hf;
}
SrsHttpResponseWriter::SrsHttpResponseWriter(ISrsProtocolReadWriter* io)
{
writer_ = new SrsHttpMessageWriter(io, this);
status = SRS_CONSTS_HTTP_OK;
}
SrsHttpResponseWriter::~SrsHttpResponseWriter()
{
srs_freep(writer_);
}
void SrsHttpResponseWriter::set_header_filter(ISrsHttpHeaderFilter* hf)
{
writer_->set_header_filter(hf);
}
srs_error_t SrsHttpResponseWriter::final_request()
{
return writer_->final_request();
}
SrsHttpHeader* SrsHttpResponseWriter::header()
{
return writer_->header();
}
srs_error_t SrsHttpResponseWriter::write(char* data, int size)
{
return writer_->write(data, size);
}
srs_error_t SrsHttpResponseWriter::writev(const iovec* iov, int iovcnt, ssize_t* pnwrite)
{
return writer_->writev(iov, iovcnt, pnwrite);
}
void SrsHttpResponseWriter::write_header(int code)
{
if (writer_->header_wrote()) {
srs_warn("http: multiple write_header calls, status=%d, code=%d", status, code);
return;
}
status = code;
return writer_->write_header();
}
srs_error_t SrsHttpResponseWriter::build_first_line(std::stringstream& ss, char* data, int size)
{
srs_error_t err = srs_success;
// Write status line for response.
ss << "HTTP/1.1 " << status << " " << srs_generate_http_status_text(status) << SRS_HTTP_CRLF;
// Try to detect content type from response body data.
SrsHttpHeader* hdr = writer_->header();
if (srs_go_http_body_allowd(status)) {
if (data && hdr->content_type().empty()) {
hdr->set_content_type(srs_go_http_detect(data, size));
}
}
return err;
}
void SrsHttpResponseWriter::write_default_header()
{
write_header(SRS_CONSTS_HTTP_OK);
}
SrsHttpRequestWriter::SrsHttpRequestWriter(ISrsProtocolReadWriter* io)
{
writer_ = new SrsHttpMessageWriter(io, this);
method_ = NULL;
path_ = NULL;
}
SrsHttpRequestWriter::~SrsHttpRequestWriter()
{
srs_freep(writer_);
}
srs_error_t SrsHttpRequestWriter::final_request()
{
return writer_->final_request();
}
SrsHttpHeader* SrsHttpRequestWriter::header()
{
return writer_->header();
}
srs_error_t SrsHttpRequestWriter::write(char* data, int size)
{
return writer_->write(data, size);
}
srs_error_t SrsHttpRequestWriter::writev(const iovec* iov, int iovcnt, ssize_t* pnwrite)
{
return writer_->writev(iov, iovcnt, pnwrite);
}
void SrsHttpRequestWriter::write_header(const char* method, const char* path)
{
if (writer_->header_wrote()) {
srs_warn("http: multiple write_header calls, current=%s(%s), now=%s(%s)", method_, path_, method, path);
return;
}
method_ = method;
path_ = path;
return writer_->write_header();
}
srs_error_t SrsHttpRequestWriter::build_first_line(std::stringstream& ss, char* data, int size)
{
srs_error_t err = srs_success;
// Write status line for response.
ss << method_ << " " << path_ << " HTTP/1.1" << SRS_HTTP_CRLF;
// Try to detect content type from request body data.
SrsHttpHeader* hdr = writer_->header();
if (data && hdr->content_type().empty()) {
hdr->set_content_type(srs_go_http_detect(data, size));
}
return err;
}
void SrsHttpRequestWriter::write_default_header()
{
write_header("GET", "/");
}
SrsHttpResponseReader::SrsHttpResponseReader(SrsHttpMessage* msg, ISrsReader* reader, SrsFastStream* body)
{
skt = reader;