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:
parent
dae46a59ae
commit
1e6143e2eb
9 changed files with 456 additions and 79 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue