mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Refactor header of HTTP message by using SrsHttpHeader.
This commit is contained in:
parent
dcb7b6aae0
commit
ca2b68f428
6 changed files with 95 additions and 120 deletions
|
@ -664,12 +664,7 @@ srs_error_t SrsGoApiRequests::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
|
|||
// request headers
|
||||
SrsJsonObject* headers = SrsJsonAny::object();
|
||||
data->set("headers", headers);
|
||||
|
||||
for (int i = 0; i < r->request_header_count(); i++) {
|
||||
std::string key = r->request_header_key_at(i);
|
||||
std::string value = r->request_header_value_at(i);
|
||||
headers->set(key, SrsJsonAny::str(value.c_str()));
|
||||
}
|
||||
r->header()->dumps(headers);
|
||||
|
||||
// server informations
|
||||
SrsJsonObject* server = SrsJsonAny::object();
|
||||
|
|
|
@ -173,6 +173,20 @@ void SrsHttpHeader::del(string key)
|
|||
}
|
||||
}
|
||||
|
||||
int SrsHttpHeader::count()
|
||||
{
|
||||
return (int)headers.size();
|
||||
}
|
||||
|
||||
void SrsHttpHeader::dumps(SrsJsonObject* o)
|
||||
{
|
||||
map<string, string>::iterator it;
|
||||
for (it = headers.begin(); it != headers.end(); ++it) {
|
||||
string v = it->second;
|
||||
o->set(it->first, SrsJsonAny::str(v.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
int64_t SrsHttpHeader::content_length()
|
||||
{
|
||||
std::string cl = get("Content-Length");
|
||||
|
@ -776,13 +790,8 @@ srs_error_t SrsHttpCorsMux::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessag
|
|||
|
||||
// If CORS enabled, and there is a "Origin" header, it's CORS.
|
||||
if (enabled) {
|
||||
for (int i = 0; i < r->request_header_count(); i++) {
|
||||
string k = r->request_header_key_at(i);
|
||||
if (k == "Origin" || k == "origin") {
|
||||
required = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SrsHttpHeader* h = r->header();
|
||||
required = !h->get("Origin").empty();
|
||||
}
|
||||
|
||||
// When CORS required, set the CORS headers.
|
||||
|
|
|
@ -45,6 +45,7 @@ class SrsHttpHeader;
|
|||
class ISrsHttpMessage;
|
||||
class SrsHttpMuxEntry;
|
||||
class ISrsHttpResponseWriter;
|
||||
class SrsJsonObject;
|
||||
|
||||
// From http specification
|
||||
// CR = <US-ASCII CR, carriage return (13)>
|
||||
|
@ -129,6 +130,11 @@ public:
|
|||
// Delete the http header indicated by key.
|
||||
// Return the removed header field.
|
||||
virtual void del(std::string);
|
||||
// Get the count of headers.
|
||||
virtual int count();
|
||||
public:
|
||||
// Dumps to a JSON object.
|
||||
virtual void dumps(SrsJsonObject* o);
|
||||
public:
|
||||
// Get the content length. -1 if not set.
|
||||
virtual int64_t content_length();
|
||||
|
@ -505,9 +511,7 @@ public:
|
|||
// then query_get("start") is "100", and query_get("end") is "200"
|
||||
virtual std::string query_get(std::string key) = 0;
|
||||
// Get the headers.
|
||||
virtual int request_header_count() = 0;
|
||||
virtual std::string request_header_key_at(int index) = 0;
|
||||
virtual std::string request_header_value_at(int index) = 0;
|
||||
virtual SrsHttpHeader* header() = 0;
|
||||
public:
|
||||
// Whether the current request is JSONP,
|
||||
// which has a "callback=xxx" in QueryString.
|
||||
|
|
|
@ -39,11 +39,13 @@ using namespace std;
|
|||
SrsHttpParser::SrsHttpParser()
|
||||
{
|
||||
buffer = new SrsFastStream();
|
||||
header = NULL;
|
||||
}
|
||||
|
||||
SrsHttpParser::~SrsHttpParser()
|
||||
{
|
||||
srs_freep(buffer);
|
||||
srs_freep(header);
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpParser::initialize(enum http_parser_type type, bool allow_jsonp)
|
||||
|
@ -70,19 +72,22 @@ srs_error_t SrsHttpParser::initialize(enum http_parser_type type, bool allow_jso
|
|||
|
||||
srs_error_t SrsHttpParser::parse_message(ISrsReader* reader, ISrsHttpMessage** ppmsg)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
*ppmsg = NULL;
|
||||
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// reset request data.
|
||||
field_name = "";
|
||||
field_value = "";
|
||||
expect_field_name = true;
|
||||
// Reset request data.
|
||||
state = SrsHttpParseStateInit;
|
||||
header = http_parser();
|
||||
hp_header = http_parser();
|
||||
// Reset the message url.
|
||||
url = "";
|
||||
headers.clear();
|
||||
// The body that we have read from cache.
|
||||
pbody = NULL;
|
||||
// Reset the temporarily parsed header field.
|
||||
expect_field_name = true;
|
||||
// The header of the request.
|
||||
srs_freep(header);
|
||||
header = new SrsHttpHeader();
|
||||
|
||||
// do parse
|
||||
if ((err = parse_message_imp(reader)) != srs_success) {
|
||||
|
@ -93,11 +98,9 @@ srs_error_t SrsHttpParser::parse_message(ISrsReader* reader, ISrsHttpMessage** p
|
|||
SrsHttpMessage* msg = new SrsHttpMessage(reader, buffer);
|
||||
|
||||
// Initialize the basic information.
|
||||
bool keep_alive = http_should_keep_alive(&header);
|
||||
msg->set_basic(header.method, header.status_code, header.content_length, keep_alive);
|
||||
|
||||
// initalize http msg, parse url.
|
||||
if ((err = msg->update(url, jsonp, headers)) != srs_success) {
|
||||
msg->set_basic(hp_header.method, hp_header.status_code, hp_header.content_length);
|
||||
msg->set_header(header, http_should_keep_alive(&hp_header));
|
||||
if ((err = msg->set_url(url, jsonp)) != srs_success) {
|
||||
srs_freep(msg);
|
||||
return srs_error_wrap(err, "update message");
|
||||
}
|
||||
|
@ -142,11 +145,6 @@ srs_error_t SrsHttpParser::parse_message_imp(ISrsReader* reader)
|
|||
}
|
||||
}
|
||||
|
||||
// parse last header.
|
||||
if (!field_name.empty() && !field_value.empty()) {
|
||||
headers.push_back(std::make_pair(field_name, field_value));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -167,7 +165,7 @@ int SrsHttpParser::on_headers_complete(http_parser* parser)
|
|||
SrsHttpParser* obj = (SrsHttpParser*)parser->data;
|
||||
srs_assert(obj);
|
||||
|
||||
obj->header = *parser;
|
||||
obj->hp_header = *parser;
|
||||
// save the parser when header parse completed.
|
||||
obj->state = SrsHttpParseStateHeaderComplete;
|
||||
|
||||
|
@ -196,7 +194,7 @@ int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length)
|
|||
srs_assert(obj);
|
||||
|
||||
if (length > 0) {
|
||||
obj->url.append(at, (int)length);
|
||||
obj->url = string(at, (int)length);
|
||||
}
|
||||
|
||||
srs_info("Method: %d, Url: %.*s", parser->method, (int)length, at);
|
||||
|
@ -211,16 +209,12 @@ int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t l
|
|||
|
||||
// field value=>name, reap the field.
|
||||
if (!obj->expect_field_name) {
|
||||
obj->headers.push_back(std::make_pair(obj->field_name, obj->field_value));
|
||||
|
||||
// reset the field name when parsed.
|
||||
obj->field_name = "";
|
||||
obj->field_value = "";
|
||||
obj->header->set(obj->field_name, obj->field_value);
|
||||
}
|
||||
obj->expect_field_name = true;
|
||||
|
||||
if (length > 0) {
|
||||
obj->field_name.append(at, (int)length);
|
||||
obj->field_name = string(at, (int)length);
|
||||
}
|
||||
|
||||
srs_info("Header field(%d bytes): %.*s", (int)length, (int)length, at);
|
||||
|
@ -233,7 +227,7 @@ int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t l
|
|||
srs_assert(obj);
|
||||
|
||||
if (length > 0) {
|
||||
obj->field_value.append(at, (int)length);
|
||||
obj->field_value = string(at, (int)length);
|
||||
}
|
||||
obj->expect_field_name = false;
|
||||
|
||||
|
@ -281,38 +275,42 @@ SrsHttpMessage::~SrsHttpMessage()
|
|||
srs_freepa(_http_ts_send_buffer);
|
||||
}
|
||||
|
||||
void SrsHttpMessage::set_basic(uint8_t method, uint16_t status, int64_t content_length, bool keep_alive)
|
||||
void SrsHttpMessage::set_basic(uint8_t method, uint16_t status, int64_t content_length)
|
||||
{
|
||||
_method = method;
|
||||
_status = status;
|
||||
_content_length = content_length;
|
||||
_keep_alive = keep_alive;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpMessage::update(string url, bool allow_jsonp, vector<SrsHttpHeaderField>& headers)
|
||||
void SrsHttpMessage::set_header(SrsHttpHeader* header, bool keep_alive)
|
||||
{
|
||||
_header = *header;
|
||||
_keep_alive = keep_alive;
|
||||
|
||||
// whether chunked.
|
||||
chunked = (header->get("Transfer-Encoding") == "chunked");
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpMessage::set_url(string url, bool allow_jsonp)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
_url = url;
|
||||
_headers = headers;
|
||||
|
||||
// whether chunked.
|
||||
std::string transfer_encoding = get_request_header("Transfer-Encoding");
|
||||
chunked = (transfer_encoding == "chunked");
|
||||
|
||||
// parse uri from url.
|
||||
std::string host = get_request_header("Host");
|
||||
|
||||
// use server public ip when no host specified.
|
||||
|
||||
// use server public ip when host not specified.
|
||||
// to make telnet happy.
|
||||
std::string host = _header.get("Host");
|
||||
if (host.empty()) {
|
||||
host= srs_get_public_internet_address();
|
||||
}
|
||||
|
||||
// parse uri to schema/server:port/path?query
|
||||
std::string uri = "http://" + host + _url;
|
||||
|
||||
// parse uri from schema/server:port/path?query
|
||||
std::string uri = _url;
|
||||
if (!host.empty()) {
|
||||
uri = "http://" + host + _url;
|
||||
}
|
||||
if ((err = _uri->initialize(uri)) != srs_success) {
|
||||
return srs_error_wrap(err, "init uri");
|
||||
return srs_error_wrap(err, "init uri %s", uri.c_str());
|
||||
}
|
||||
|
||||
// parse ext.
|
||||
|
@ -546,39 +544,9 @@ string SrsHttpMessage::query_get(string key)
|
|||
return v;
|
||||
}
|
||||
|
||||
int SrsHttpMessage::request_header_count()
|
||||
SrsHttpHeader* SrsHttpMessage::header()
|
||||
{
|
||||
return (int)_headers.size();
|
||||
}
|
||||
|
||||
string SrsHttpMessage::request_header_key_at(int index)
|
||||
{
|
||||
srs_assert(index < request_header_count());
|
||||
SrsHttpHeaderField item = _headers[index];
|
||||
return item.first;
|
||||
}
|
||||
|
||||
string SrsHttpMessage::request_header_value_at(int index)
|
||||
{
|
||||
srs_assert(index < request_header_count());
|
||||
SrsHttpHeaderField item = _headers[index];
|
||||
return item.second;
|
||||
}
|
||||
|
||||
string SrsHttpMessage::get_request_header(string name)
|
||||
{
|
||||
std::vector<SrsHttpHeaderField>::iterator it;
|
||||
|
||||
for (it = _headers.begin(); it != _headers.end(); ++it) {
|
||||
SrsHttpHeaderField& elem = *it;
|
||||
std::string key = elem.first;
|
||||
std::string value = elem.second;
|
||||
if (key == name) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
return &_header;
|
||||
}
|
||||
|
||||
SrsRequest* SrsHttpMessage::to_request(string vhost)
|
||||
|
@ -598,7 +566,7 @@ SrsRequest* SrsHttpMessage::to_request(string vhost)
|
|||
|
||||
// generate others.
|
||||
req->tcUrl = "rtmp://" + vhost + "/" + req->app;
|
||||
req->pageUrl = get_request_header("Referer");
|
||||
req->pageUrl = _header.get("Referer");
|
||||
req->objectEncoding = 0;
|
||||
|
||||
std::string query = _uri->get_query();
|
||||
|
@ -863,7 +831,7 @@ srs_error_t SrsHttpResponseWriter::send_header(char* data, int size)
|
|||
return srs_error_wrap(err, "filter header");
|
||||
}
|
||||
|
||||
// write headers
|
||||
// write header
|
||||
hdr->write(ss);
|
||||
|
||||
// header_eof
|
||||
|
|
|
@ -37,9 +37,6 @@ class ISrsReader;
|
|||
class SrsHttpResponseReader;
|
||||
class ISrsProtocolReadWriter;
|
||||
|
||||
// For http header.
|
||||
typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
||||
|
||||
// A wrapper for http-parser,
|
||||
// provides HTTP message originted service.
|
||||
class SrsHttpParser
|
||||
|
@ -57,9 +54,9 @@ private:
|
|||
std::string field_name;
|
||||
std::string field_value;
|
||||
SrsHttpParseState state;
|
||||
http_parser header;
|
||||
http_parser hp_header;
|
||||
std::string url;
|
||||
std::vector<SrsHttpHeaderField> headers;
|
||||
SrsHttpHeader* header;
|
||||
const char* pbody;
|
||||
public:
|
||||
SrsHttpParser();
|
||||
|
@ -88,9 +85,6 @@ private:
|
|||
static int on_body(http_parser* parser, const char* at, size_t length);
|
||||
};
|
||||
|
||||
// for http header.
|
||||
typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
||||
|
||||
// A Request represents an HTTP request received by a server
|
||||
// or to be sent by a client.
|
||||
//
|
||||
|
@ -100,34 +94,36 @@ typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
|||
class SrsHttpMessage : public ISrsHttpMessage
|
||||
{
|
||||
private:
|
||||
// The parsed url.
|
||||
std::string _url;
|
||||
// The extension of file, for example, .flv
|
||||
std::string _ext;
|
||||
// The body object, reader object.
|
||||
// @remark, user can get body in string by get_body().
|
||||
SrsHttpResponseReader* _body;
|
||||
// Whether the body is chunked.
|
||||
bool chunked;
|
||||
// Whether the body is infinite chunked.
|
||||
bool infinite_chunked;
|
||||
// The uri parser
|
||||
SrsHttpUri* _uri;
|
||||
// Use a buffer to read and send ts file.
|
||||
// TODO: FIXME: remove it.
|
||||
char* _http_ts_send_buffer;
|
||||
// The http headers
|
||||
std::vector<SrsHttpHeaderField> _headers;
|
||||
// The query map
|
||||
std::map<std::string, std::string> _query;
|
||||
// The transport connection, can be NULL.
|
||||
SrsConnection* owner_conn;
|
||||
private:
|
||||
uint8_t _method;
|
||||
uint16_t _status;
|
||||
int64_t _content_length;
|
||||
private:
|
||||
// The http headers
|
||||
SrsHttpHeader _header;
|
||||
// Whether the request indicates should keep alive for the http connection.
|
||||
bool _keep_alive;
|
||||
// Whether the body is chunked.
|
||||
bool chunked;
|
||||
private:
|
||||
// The parsed url.
|
||||
std::string _url;
|
||||
// The extension of file, for example, .flv
|
||||
std::string _ext;
|
||||
// The uri parser
|
||||
SrsHttpUri* _uri;
|
||||
// The query map
|
||||
std::map<std::string, std::string> _query;
|
||||
private:
|
||||
// Whether request is jsonp.
|
||||
bool jsonp;
|
||||
|
@ -138,9 +134,11 @@ public:
|
|||
virtual ~SrsHttpMessage();
|
||||
public:
|
||||
// Set the basic information for HTTP request.
|
||||
virtual void set_basic(uint8_t method, uint16_t status, int64_t content_length, bool keep_alive);
|
||||
virtual void set_basic(uint8_t method, uint16_t status, int64_t content_length);
|
||||
// Set HTTP header and whether the request require keep alive.
|
||||
virtual void set_header(SrsHttpHeader* header, bool keep_alive);
|
||||
// set the original messages, then update the message.
|
||||
virtual srs_error_t update(std::string url, bool allow_jsonp, std::vector<SrsHttpHeaderField>& headers);
|
||||
virtual srs_error_t set_url(std::string url, bool allow_jsonp);
|
||||
public:
|
||||
// Get the owner connection, maybe NULL.
|
||||
virtual SrsConnection* connection();
|
||||
|
@ -187,10 +185,7 @@ public:
|
|||
// then query_get("start") is "100", and query_get("end") is "200"
|
||||
virtual std::string query_get(std::string key);
|
||||
// Get the headers.
|
||||
virtual int request_header_count();
|
||||
virtual std::string request_header_key_at(int index);
|
||||
virtual std::string request_header_value_at(int index);
|
||||
virtual std::string get_request_header(std::string name);
|
||||
virtual SrsHttpHeader* header();
|
||||
public:
|
||||
// Convert the http message to a request.
|
||||
// @remark user must free the return request.
|
||||
|
|
|
@ -134,6 +134,7 @@ VOID TEST(ProtocolHTTPTest, HTTPHeader)
|
|||
SrsHttpHeader h;
|
||||
h.set("Server", "SRS");
|
||||
EXPECT_STREQ("SRS", h.get("Server").c_str());
|
||||
EXPECT_EQ(1, h.count());
|
||||
|
||||
stringstream ss;
|
||||
h.write(ss);
|
||||
|
@ -141,17 +142,20 @@ VOID TEST(ProtocolHTTPTest, HTTPHeader)
|
|||
|
||||
h.del("Server");
|
||||
EXPECT_TRUE(h.get("Server").empty());
|
||||
EXPECT_EQ(0, h.count());
|
||||
|
||||
EXPECT_EQ(-1, h.content_length());
|
||||
|
||||
h.set_content_length(0);
|
||||
EXPECT_EQ(0, h.content_length());
|
||||
EXPECT_EQ(1, h.count());
|
||||
|
||||
h.set_content_length(1024);
|
||||
EXPECT_EQ(1024, h.content_length());
|
||||
|
||||
h.set_content_type("text/plain");
|
||||
EXPECT_STREQ("text/plain", h.content_type().c_str());
|
||||
EXPECT_EQ(2, h.count());
|
||||
}
|
||||
|
||||
VOID TEST(ProtocolHTTPTest, HTTPCommonHandler)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue