From 0186247feef4c05f31974383a2403bdc79a217ec Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 18 May 2014 17:57:20 +0800 Subject: [PATCH] support http api json, to PUT/POST. 0.9.105 --- README.md | 5 ++ trunk/src/app/srs_app_http.cpp | 86 ++++++++++++++++++++++++++++-- trunk/src/app/srs_app_http.hpp | 12 +++++ trunk/src/app/srs_app_http_api.cpp | 75 +++++++++++++++++++++++++- trunk/src/app/srs_app_http_api.hpp | 11 ++++ trunk/src/core/srs_core.hpp | 6 +-- 6 files changed, 187 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 31526f70a..a731ebb78 100755 --- a/README.md +++ b/README.md @@ -229,6 +229,11 @@ Supported operating systems and hardware: * 2013-10-17, Created.
## History +* v1.0, 2014-05-18, support http api json, to PUT/POST. 0.9.105 +* v1.0, 2014-05-17, fix #72, also need stream_id for send_and_free_message. 0.9.101 +* v1.0, 2014-05-17, rename struct to class. 0.9.100 +* v1.0, 2014-05-14, fix #67 pithy print, stage must has a age. 0.9.98 +* v1.0, 2014-05-13, fix mem leak for delete[] SharedPtrMessage array. 0.9.95 * v1.0, 2014-05-12, refine the kbps calc module. 0.9.93 * v1.0, 2014-05-08, edge support FMS origin server. 0.9.92 * v1.0, 2014-04-28, [1.0 mainline2(0.9.79)](https://github.com/winlinvip/simple-rtmp-server/releases/tag/1.0.mainline2) released. 35255 lines. diff --git a/trunk/src/app/srs_app_http.cpp b/trunk/src/app/srs_app_http.cpp index 4999896dd..15e6c648a 100644 --- a/trunk/src/app/srs_app_http.cpp +++ b/trunk/src/app/srs_app_http.cpp @@ -217,7 +217,7 @@ int SrsHttpHandler::best_match(const char* path, int length, SrsHttpHandlerMatch SrsHttpHandler* SrsHttpHandler::res_status_line(stringstream& ss) { ss << "HTTP/1.1 200 OK " << __CRLF - << "Server: SRS/"RTMP_SIG_SRS_VERSION"" << __CRLF; + << "Server: "RTMP_SIG_SRS_KEY"/"RTMP_SIG_SRS_VERSION"" << __CRLF; return this; } @@ -597,11 +597,28 @@ bool SrsHttpMessage::is_http_delete() return _header.method == HTTP_DELETE; } +string SrsHttpMessage::uri() +{ + std::string uri = _uri->get_schema(); + if (uri.empty()) { + uri += "http://"; + } + + uri += host(); + uri += path(); + return uri; +} + string SrsHttpMessage::url() { return _uri->get_url(); } +string SrsHttpMessage::host() +{ + return get_request_header("Host"); +} + string SrsHttpMessage::path() { return _uri->get_path(); @@ -683,6 +700,46 @@ void SrsHttpMessage::append_body(const char* body, int length) _body->append(body, length); } +int SrsHttpMessage::request_header_count() +{ + 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; +} + +void SrsHttpMessage::set_request_header(string key, string value) +{ + headers.push_back(std::make_pair(key, value)); +} + +string SrsHttpMessage::get_request_header(string name) +{ + std::vector::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 ""; +} + SrsHttpParser::SrsHttpParser() { msg = NULL; @@ -723,6 +780,9 @@ int SrsHttpParser::parse_message(SrsSocket* skt, SrsHttpMessage** ppmsg) srs_assert(msg == NULL); msg = new SrsHttpMessage(); + // reset request data. + filed_name = ""; + // reset response header. msg->reset(); @@ -827,14 +887,34 @@ int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length) return 0; } -int SrsHttpParser::on_header_field(http_parser* /*parser*/, const char* at, size_t length) +int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t length) { + SrsHttpParser* obj = (SrsHttpParser*)parser->data; + + if (length > 0) { + srs_assert(obj); + obj->filed_name.append(at, (int)length); + } + srs_info("Header field: %.*s", (int)length, at); return 0; } -int SrsHttpParser::on_header_value(http_parser* /*parser*/, const char* at, size_t length) +int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t length) { + SrsHttpParser* obj = (SrsHttpParser*)parser->data; + + if (length > 0) { + srs_assert(obj); + srs_assert(obj->msg); + + std::string field_value; + field_value.append(at, (int)length); + + obj->msg->set_request_header(obj->filed_name, field_value); + obj->filed_name = ""; + } + srs_info("Header value: %.*s", (int)length, at); return 0; } diff --git a/trunk/src/app/srs_app_http.hpp b/trunk/src/app/srs_app_http.hpp index 9c54aa1e6..525a69985 100644 --- a/trunk/src/app/srs_app_http.hpp +++ b/trunk/src/app/srs_app_http.hpp @@ -323,6 +323,9 @@ private: * use a buffer to read and send ts file. */ char* _http_ts_send_buffer; + // http headers + typedef std::pair SrsHttpHeaderField; + std::vector headers; public: SrsHttpMessage(); virtual ~SrsHttpMessage(); @@ -337,7 +340,9 @@ public: virtual bool is_http_put(); virtual bool is_http_post(); virtual bool is_http_delete(); + virtual std::string uri(); virtual std::string url(); + virtual std::string host(); virtual std::string path(); virtual std::string query(); virtual std::string body(); @@ -352,6 +357,12 @@ public: virtual void set_match(SrsHttpHandlerMatch* match); virtual void set_requires_crossdomain(bool requires_crossdomain); virtual void append_body(const char* body, int length); +public: + virtual int request_header_count(); + virtual std::string request_header_key_at(int index); + virtual std::string request_header_value_at(int index); + virtual void set_request_header(std::string key, std::string value); + virtual std::string get_request_header(std::string name); }; /** @@ -364,6 +375,7 @@ private: http_parser_settings settings; http_parser parser; SrsHttpMessage* msg; + std::string filed_name; public: SrsHttpParser(); virtual ~SrsHttpParser(); diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 7c9980aeb..bf477ee67 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -124,6 +124,7 @@ SrsApiV1::SrsApiV1() handlers.push_back(new SrsApiMemInfos()); handlers.push_back(new SrsApiAuthors()); handlers.push_back(new SrsApiConfigs()); + handlers.push_back(new SrsApiRequests()); } SrsApiV1::~SrsApiV1() @@ -149,7 +150,72 @@ int SrsApiV1::do_process_request(SrsSocket* skt, SrsHttpMessage* req) << JFIELD_STR("system_proc_stats", "the system process stats") << JFIELD_CONT << JFIELD_STR("meminfos", "the meminfo of system") << JFIELD_CONT << JFIELD_STR("configs", "to query or modify the config of srs") << JFIELD_CONT - << JFIELD_STR("authors", "the primary authors and contributors") + << JFIELD_STR("authors", "the primary authors and contributors") << JFIELD_CONT + << JFIELD_STR("requests", "the request itself, for http debug") + << JOBJECT_END + << JOBJECT_END; + + return res_json(skt, req, ss.str()); +} + +SrsApiRequests::SrsApiRequests() +{ +} + +SrsApiRequests::~SrsApiRequests() +{ +} + +bool SrsApiRequests::can_handle(const char* path, int length, const char** /*pchild*/) +{ + return srs_path_equals("/requests", path, length); +} + +int SrsApiRequests::do_process_request(SrsSocket* skt, SrsHttpMessage* req) +{ + std::stringstream ss; + + ss << JOBJECT_START + << JFIELD_ERROR(ERROR_SUCCESS) << JFIELD_CONT + << JFIELD_ORG("data", JOBJECT_START) + << JFIELD_STR("uri", req->uri()) << JFIELD_CONT + << JFIELD_STR("path", req->path()) << JFIELD_CONT; + + // method + if (req->is_http_get()) { + ss << JFIELD_STR("METHOD", "GET"); + } else if (req->is_http_post()) { + ss << JFIELD_STR("METHOD", "POST"); + } else if (req->is_http_put()) { + ss << JFIELD_STR("METHOD", "PUT"); + } else if (req->is_http_delete()) { + ss << JFIELD_STR("METHOD", "DELETE"); + } else { + ss << JFIELD_ORG("METHOD", req->method()); + } + ss << JFIELD_CONT; + + // request headers + ss << JFIELD_NAME("headers") << JOBJECT_START; + for (int i = 0; i < req->request_header_count(); i++) { + std::string key = req->request_header_key_at(i); + std::string value = req->request_header_value_at(i); + if ( i < req->request_header_count() - 1) { + ss << JFIELD_STR(key, value) << JFIELD_CONT; + } else { + ss << JFIELD_STR(key, value); + } + } + ss << JOBJECT_END << JFIELD_CONT; + + // server informations + ss << JFIELD_NAME("server") << JOBJECT_START + << JFIELD_STR("sigature", RTMP_SIG_SRS_KEY) << JFIELD_CONT + << JFIELD_STR("name", RTMP_SIG_SRS_NAME) << JFIELD_CONT + << JFIELD_STR("version", RTMP_SIG_SRS_VERSION) << JFIELD_CONT + << JFIELD_STR("link", RTMP_SIG_SRS_URL) << JFIELD_CONT + << JFIELD_ORG("time", srs_get_system_time_ms()) + << JOBJECT_END << JOBJECT_END << JOBJECT_END; @@ -177,7 +243,12 @@ int SrsApiConfigs::do_process_request(SrsSocket* skt, SrsHttpMessage* req) ss << JOBJECT_START << JFIELD_ERROR(ERROR_SUCCESS) << JFIELD_CONT << JFIELD_ORG("urls", JOBJECT_START) - << JFIELD_STR("logs", "the log level, tank and path") + << JFIELD_NAME("logs") << JOBJECT_START + << JFIELD_STR("uri", req->uri()+"/logs") << JFIELD_CONT + << JFIELD_STR("desc", "system log settings") << JFIELD_CONT + << JFIELD_STR("GET", "query logs tank/level/file") << JFIELD_CONT + << JFIELD_STR("PUT", "update logs tank/level/file") + << JOBJECT_END << JOBJECT_END << JOBJECT_END; diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 0a3de21d9..b94938b23 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -76,6 +76,17 @@ protected: virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); }; +class SrsApiRequests : public SrsHttpHandler +{ +public: + SrsApiRequests(); + virtual ~SrsApiRequests(); +public: + virtual bool can_handle(const char* path, int length, const char** pchild); +protected: + virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); +}; + class SrsApiConfigs : public SrsHttpHandler { public: diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 0ffbd80b4..eb017d71c 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,12 +31,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR "0" #define VERSION_MINOR "9" -#define VERSION_REVISION "104" +#define VERSION_REVISION "105" #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION // server info. -#define RTMP_SIG_SRS_KEY "srs" +#define RTMP_SIG_SRS_KEY "SRS" #define RTMP_SIG_SRS_ROLE "origin/edge server" -#define RTMP_SIG_SRS_NAME RTMP_SIG_SRS_KEY"(simple rtmp server)" +#define RTMP_SIG_SRS_NAME RTMP_SIG_SRS_KEY"(Simple RTMP Server)" #define RTMP_SIG_SRS_URL_SHORT "github.com/winlinvip/simple-rtmp-server" #define RTMP_SIG_SRS_URL "https://"RTMP_SIG_SRS_URL_SHORT #define RTMP_SIG_SRS_WEB "http://blog.csdn.net/win_lin"