diff --git a/trunk/configure b/trunk/configure index 270ca9c19..62cf93fec 100755 --- a/trunk/configure +++ b/trunk/configure @@ -427,7 +427,7 @@ MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_socke "srs_app_codec" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" "srs_app_pithy_print" "srs_app_reload" "srs_app_http_api" - "srs_app_http_conn" "srs_app_http_hooks") + "srs_app_http_conn" "srs_app_http_hooks" "srs_app_json") APP_INCS="src/app"; MODULE_DIR=${APP_INCS} . auto/modules.sh APP_OBJS="${MODULE_OBJS[@]}" # diff --git a/trunk/src/app/srs_app_http.cpp b/trunk/src/app/srs_app_http.cpp index 6fb92e1c8..0494771d2 100644 --- a/trunk/src/app/srs_app_http.cpp +++ b/trunk/src/app/srs_app_http.cpp @@ -39,6 +39,22 @@ using namespace std; #define SRS_HTTP_HEADER_BUFFER 1024 +bool srs_path_equals(const char* expect, const char* path, int nb_path) +{ + int size = strlen(expect); + + if (size != nb_path) { + return false; + } + + return !memcmp(expect, path, size); +} + +SrsHttpHandlerMatch::SrsHttpHandlerMatch() +{ + handler = NULL; +} + SrsHttpHandler::SrsHttpHandler() { } @@ -59,21 +75,34 @@ int SrsHttpHandler::initialize() return ret; } -bool SrsHttpHandler::can_handle(const char* /*path*/, int /*length*/, const char** /*pnext_path*/) +bool SrsHttpHandler::can_handle(const char* /*path*/, int /*length*/, const char** /*pchild*/) { return false; } -int SrsHttpHandler::process_request(SrsSocket* /*skt*/, SrsHttpMessage* /*req*/, const char* /*path*/, int /*length*/) +int SrsHttpHandler::process_request(SrsSocket* skt, SrsHttpMessage* req) +{ + if (req->method() == HTTP_OPTIONS) { + return res_options(skt); + } + + return do_process_request(skt, req); +} + +int SrsHttpHandler::do_process_request(SrsSocket* /*skt*/, SrsHttpMessage* /*req*/) { int ret = ERROR_SUCCESS; return ret; } -int SrsHttpHandler::best_match(const char* path, int length, SrsHttpHandler** phandler, const char** pstart, int* plength) +int SrsHttpHandler::best_match(const char* path, int length, SrsHttpHandlerMatch** ppmatch) { int ret = ERROR_SUCCESS; + SrsHttpHandler* handler = NULL; + const char* match_start = NULL; + int match_length = 0; + for (;;) { // ensure cur is not NULL. // ensure p not NULL and has bytes to parse. @@ -86,23 +115,23 @@ int SrsHttpHandler::best_match(const char* path, int length, SrsHttpHandler** ph } // whether the handler can handler the node. - const char* pnext = p; - if (!can_handle(path, p - path, &pnext)) { + const char* pchild = p; + if (!can_handle(path, p - path, &pchild)) { break; } // save current handler, it's ok for current handler atleast. - *phandler = this; - *pstart = path; - *plength = p - path; + handler = this; + match_start = path; + match_length = p - path; // find the best matched child handler. std::vector::iterator it; for (it = handlers.begin(); it != handlers.end(); ++it) { - SrsHttpHandler* handler = *it; + SrsHttpHandler* h = *it; // matched, donot search more. - if (handler->best_match(pnext, length - (pnext - path), phandler, pstart, plength) == ERROR_SUCCESS) { + if (h->best_match(pchild, length - (pchild - path), ppmatch) == ERROR_SUCCESS) { break; } } @@ -111,11 +140,22 @@ int SrsHttpHandler::best_match(const char* path, int length, SrsHttpHandler** ph break; } - if (*phandler == NULL) { + // if already matched by child, return. + if (*ppmatch) { + return ret; + } + + // not matched, error. + if (handler == NULL) { ret = ERROR_HTTP_HANDLER_MATCH_URL; return ret; } + // matched by this handler. + *ppmatch = new SrsHttpHandlerMatch(); + (*ppmatch)->handler = handler; + (*ppmatch)->matched_url.append(match_start, match_length); + return ret; } @@ -133,6 +173,13 @@ SrsHttpHandler* SrsHttpHandler::res_content_type(std::stringstream& ss) return this; } +SrsHttpHandler* SrsHttpHandler::res_content_type_json(std::stringstream& ss) +{ + ss << "Content-Type: application/json;charset=utf-8" << __CRLF + << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF; + return this; +} + SrsHttpHandler* SrsHttpHandler::res_content_length(std::stringstream& ss, int64_t length) { ss << "Content-Length: "<< length << __CRLF; @@ -189,6 +236,18 @@ int SrsHttpHandler::res_text(SrsSocket* skt, std::string body) return res_flush(skt, ss); } +int SrsHttpHandler::res_json(SrsSocket* skt, std::string json) +{ + std::stringstream ss; + + res_status_line(ss)->res_content_type_json(ss) + ->res_content_length(ss, (int)json.length())->res_enable_crossdomain(ss) + ->res_header_eof(ss) + ->res_body(ss, json); + + return res_flush(skt, ss); +} + SrsHttpHandler* SrsHttpHandler::create_http_api() { return new SrsApiRoot(); @@ -204,11 +263,15 @@ SrsHttpMessage::SrsHttpMessage() { _body = new SrsBuffer(); _state = SrsHttpParseStateInit; + _uri = new SrsHttpUri(); + _match = NULL; } SrsHttpMessage::~SrsHttpMessage() { srs_freep(_body); + srs_freep(_uri); + srs_freep(_match); } void SrsHttpMessage::reset() @@ -218,6 +281,11 @@ void SrsHttpMessage::reset() _url = ""; } +int SrsHttpMessage::parse_uri() +{ + return _uri->initialize(_url); +} + bool SrsHttpMessage::is_complete() { return _state == SrsHttpParseStateComplete; @@ -230,7 +298,17 @@ u_int8_t SrsHttpMessage::method() string SrsHttpMessage::url() { - return _url; + return _uri->get_url(); +} + +string SrsHttpMessage::path() +{ + return _uri->get_path(); +} + +string SrsHttpMessage::query() +{ + return _uri->get_query(); } string SrsHttpMessage::body() @@ -254,6 +332,11 @@ int64_t SrsHttpMessage::content_length() return _header.content_length; } +SrsHttpHandlerMatch* SrsHttpMessage::match() +{ + return _match; +} + void SrsHttpMessage::set_url(std::string url) { _url = url; @@ -269,6 +352,12 @@ void SrsHttpMessage::set_header(http_parser* header) memcpy(&_header, header, sizeof(http_parser)); } +void SrsHttpMessage::set_match(SrsHttpHandlerMatch* match) +{ + srs_freep(_match); + _match = match; +} + void SrsHttpMessage::append_body(const char* body, int length) { _body->append(body, length); @@ -489,22 +578,25 @@ int SrsHttpUri::initialize(std::string _url) path = get_uri_field(url, &hp_u, UF_PATH); srs_info("parse url %s success", purl); + query = get_uri_field(url, &hp_u, UF_QUERY); + srs_trace("parse query %s success", purl); + return ret; } const char* SrsHttpUri::get_url() { - return url.c_str(); + return url.data(); } const char* SrsHttpUri::get_schema() { - return schema.c_str(); + return schema.data(); } const char* SrsHttpUri::get_host() { - return host.c_str(); + return host.data(); } int SrsHttpUri::get_port() @@ -514,7 +606,12 @@ int SrsHttpUri::get_port() const char* SrsHttpUri::get_path() { - return path.c_str(); + return path.data(); +} + +const char* SrsHttpUri::get_query() +{ + return path.data(); } std::string SrsHttpUri::get_uri_field(std::string uri, http_parser_url* hp_u, http_parser_url_fields field) diff --git a/trunk/src/app/srs_app_http.hpp b/trunk/src/app/srs_app_http.hpp index 1b569f794..a4a913d8a 100644 --- a/trunk/src/app/srs_app_http.hpp +++ b/trunk/src/app/srs_app_http.hpp @@ -42,7 +42,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class SrsBuffer; class SrsRequest; class SrsSocket; +class SrsHttpUri; class SrsHttpMessage; +class SrsHttpHandler; // http specification // CR = @@ -62,6 +64,12 @@ class SrsHttpMessage; // linux path seprator #define __PATH_SEP '/' +// query string seprator +#define __QUERY_SEP '?' + +// compare the path. +// full compare, extractly match. +extern bool srs_path_equals(const char* expect, const char* path, int nb_path); // state of message enum SrsHttpParseState { @@ -70,6 +78,18 @@ enum SrsHttpParseState { SrsHttpParseStateComplete }; +/** +* the matched handler info. +*/ +class SrsHttpHandlerMatch +{ +public: + SrsHttpHandler* handler; + std::string matched_url; +public: + SrsHttpHandlerMatch(); +}; + /** * resource handler for HTTP RESTful api. */ @@ -90,21 +110,29 @@ public: virtual int initialize(); /** * whether current handler can handle the specified path. - * @pnext_path set the next path, if needed. + * @pchild set the next child path, if needed. + * for example, the root handler will reset pchild to path, + * to reparse the path use child handlers. */ - virtual bool can_handle(const char* path, int length, const char** pnext_path); + virtual bool can_handle(const char* path, int length, const char** pchild); /** * use the handler to process the request. + * @remark sub classes should override the do_process_request. */ - virtual int process_request(SrsSocket* skt, SrsHttpMessage* req, const char* path, int length); + virtual int process_request(SrsSocket* skt, SrsHttpMessage* req); public: /** * find the best matched handler */ - virtual int best_match(const char* path, int length, SrsHttpHandler** phandler, const char** pstart, int* plength); + virtual int best_match(const char* path, int length, SrsHttpHandlerMatch** ppmatch); +// factory methods +protected: + virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); +// response writer public: virtual SrsHttpHandler* res_status_line(std::stringstream& ss); virtual SrsHttpHandler* res_content_type(std::stringstream& ss); + virtual SrsHttpHandler* res_content_type_json(std::stringstream& ss); virtual SrsHttpHandler* res_content_length(std::stringstream& ss, int64_t length); virtual SrsHttpHandler* res_enable_crossdomain(std::stringstream& ss); virtual SrsHttpHandler* res_header_eof(std::stringstream& ss); @@ -113,6 +141,8 @@ public: public: virtual int res_options(SrsSocket* skt); virtual int res_text(SrsSocket* skt, std::string body); + virtual int res_json(SrsSocket* skt, std::string json); +// object creator public: /** * create http api resource handler. @@ -148,23 +178,34 @@ private: * @remark, user can use is_complete() to determine the state. */ SrsHttpParseState _state; - + /** + * uri parser + */ + SrsHttpUri* _uri; + /** + * best matched handler. + */ + SrsHttpHandlerMatch* _match; public: SrsHttpMessage(); virtual ~SrsHttpMessage(); - public: virtual void reset(); + virtual int parse_uri(); public: virtual bool is_complete(); virtual u_int8_t method(); virtual std::string url(); + virtual std::string path(); + virtual std::string query(); virtual std::string body(); virtual int64_t body_size(); virtual int64_t content_length(); + virtual SrsHttpHandlerMatch* match(); virtual void set_url(std::string url); virtual void set_state(SrsHttpParseState state); virtual void set_header(http_parser* header); + virtual void set_match(SrsHttpHandlerMatch* match); virtual void append_body(const char* body, int length); }; @@ -220,6 +261,7 @@ private: std::string host; int port; std::string path; + std::string query; public: SrsHttpUri(); virtual ~SrsHttpUri(); @@ -234,6 +276,7 @@ public: virtual const char* get_host(); virtual int get_port(); virtual const char* get_path(); + virtual const char* get_query(); private: /** * get the parsed url field. diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 0a74091a9..6bcbc2f13 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -33,6 +33,7 @@ using namespace std; #include #include #include +#include SrsApiRoot::SrsApiRoot() { @@ -43,24 +44,28 @@ SrsApiRoot::~SrsApiRoot() { } -bool SrsApiRoot::can_handle(const char* path, int length, const char** pnext_path) +bool SrsApiRoot::can_handle(const char* path, int length, const char** pchild) { - // reset the next path for child to parse. - *pnext_path = path; + // reset the child path to path, + // for child to reparse the path. + *pchild = path; - return true; + // only compare the first char. + return srs_path_equals("/", path, 1); } -int SrsApiRoot::process_request(SrsSocket* skt, SrsHttpMessage* req, const char* /*path*/, int /*length*/) +int SrsApiRoot::do_process_request(SrsSocket* skt, SrsHttpMessage* req) { - if (req->method() == HTTP_OPTIONS) { - return res_options(skt); - } else { - std::string body = "hello, root"; - return res_text(skt, body); - } - - return ERROR_SUCCESS; + std::stringstream ss; + + ss << JOBJECT_START + << JFIELD_ERROR(ERROR_SUCCESS) << JFIELD_CONT + << JFIELD_ORG("urls", JOBJECT_START) + << JFIELD_STR("v1", "the api version 1.0") + << JOBJECT_END + << JOBJECT_END; + + return res_json(skt, ss.str()); } SrsApiApi::SrsApiApi() @@ -71,21 +76,15 @@ SrsApiApi::~SrsApiApi() { } -bool SrsApiApi::can_handle(const char* path, int length, const char** /*pnext_path*/) +bool SrsApiApi::can_handle(const char* path, int length, const char** /*pchild*/) { - return !memcmp("/api", path, length); + return srs_path_equals("/api", path, length); } -int SrsApiApi::process_request(SrsSocket* skt, SrsHttpMessage* req, const char* /*path*/, int /*length*/) +int SrsApiApi::do_process_request(SrsSocket* skt, SrsHttpMessage* req) { - if (req->method() == HTTP_OPTIONS) { - return res_options(skt); - } else { - std::string body = "hello, api"; - return res_text(skt, body); - } - - return ERROR_SUCCESS; + std::string body = "hello, api"; + return res_text(skt, body); } SrsHttpApi::SrsHttpApi(SrsServer* srs_server, st_netfd_t client_stfd, SrsHttpHandler* _handler) @@ -147,25 +146,31 @@ int SrsHttpApi::do_cycle() int SrsHttpApi::process_request(SrsSocket* skt, SrsHttpMessage* req) { int ret = ERROR_SUCCESS; + + // parse uri to schema/server:port/path?query + if ((ret = req->parse_uri()) != ERROR_SUCCESS) { + return ret; + } // TODO: maybe need to parse the url. - std::string uri = req->url(); + std::string url = req->path(); - int length = 0; - const char* start = NULL; - SrsHttpHandler* p = NULL; - if ((ret = handler->best_match(uri.data(), uri.length(), &p, &start, &length)) != ERROR_SUCCESS) { + SrsHttpHandlerMatch* p = NULL; + if ((ret = handler->best_match(url.data(), url.length(), &p)) != ERROR_SUCCESS) { srs_warn("failed to find the best match handler for url. ret=%d", ret); return ret; } // if success, p and pstart should be valid. srs_assert(p); - srs_assert(start); - srs_assert(length <= (int)uri.length()); + srs_assert(p->handler); + srs_assert(p->matched_url.length() <= url.length()); + srs_info("best match handler, matched_url=%s", p->matched_url.c_str()); + + req->set_match(p); // use handler to process request. - if ((ret = p->process_request(skt, req, start, length)) != ERROR_SUCCESS) { + if ((ret = p->handler->process_request(skt, req)) != ERROR_SUCCESS) { srs_warn("handler failed to process http request. ret=%d", ret); return ret; } diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 8d1f17517..83c55cc4d 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -48,8 +48,8 @@ public: SrsApiRoot(); virtual ~SrsApiRoot(); public: - virtual bool can_handle(const char* path, int length, const char** pnext_path); - virtual int process_request(SrsSocket* skt, SrsHttpMessage* req, const char* path, int length); + virtual bool can_handle(const char* path, int length, const char** pchild); + virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); }; class SrsApiApi : public SrsHttpHandler @@ -58,8 +58,8 @@ public: SrsApiApi(); virtual ~SrsApiApi(); public: - virtual bool can_handle(const char* path, int length, const char** pnext_path); - virtual int process_request(SrsSocket* skt, SrsHttpMessage* req, const char* path, int length); + virtual bool can_handle(const char* path, int length, const char** pchild); + virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); }; class SrsHttpApi : public SrsConnection diff --git a/trunk/src/app/srs_app_http_hooks.cpp b/trunk/src/app/srs_app_http_hooks.cpp index 57a87259e..7cdaca989 100644 --- a/trunk/src/app/srs_app_http_hooks.cpp +++ b/trunk/src/app/srs_app_http_hooks.cpp @@ -35,6 +35,7 @@ using namespace std; #include #include #include +#include #define SRS_HTTP_RESPONSE_OK "0" @@ -202,32 +203,14 @@ int SrsHttpHooks::on_connect(std::string url, int client_id, std::string ip, Srs } */ std::stringstream ss; - ss << "{" - // action - << '"' << "action" << '"' << ':' - << '"' << "on_connect" << '"' - << ',' - // client_id - << '"' << "client_id" << '"' << ':' - << std::dec << client_id - << ',' - // ip - << '"' << "ip" << '"' << ':' - << '"' << ip << '"' - << ',' - // vhost - << '"' << "vhost" << '"' << ':' - << '"' << req->vhost << '"' - << ',' - // app - << '"' << "app" << '"' << ':' - << '"' << req->app << '"' - << ',' - // pageUrl - << '"' << "pageUrl" << '"' << ':' - << '"' << req->pageUrl << '"' - //<< ',' - << "}"; + ss << JOBJECT_START + << JFIELD_STR("action", "on_connect") << JFIELD_CONT + << JFIELD_ORG("client_id", client_id) << JFIELD_CONT + << JFIELD_STR("ip", ip) << JFIELD_CONT + << JFIELD_STR("vhost", req->vhost) << JFIELD_CONT + << JFIELD_STR("app", req->app) << JFIELD_CONT + << JFIELD_STR("pageUrl", req->pageUrl) << JFIELD_CONT + << JOBJECT_END; std::string data = ss.str(); std::string res; @@ -273,28 +256,14 @@ void SrsHttpHooks::on_close(std::string url, int client_id, std::string ip, SrsR } */ std::stringstream ss; - ss << "{" - // action - << '"' << "action" << '"' << ':' - << '"' << "on_close" << '"' - << ',' - // client_id - << '"' << "client_id" << '"' << ':' - << std::dec << client_id - << ',' - // ip - << '"' << "ip" << '"' << ':' - << '"' << ip << '"' - << ',' - // vhost - << '"' << "vhost" << '"' << ':' - << '"' << req->vhost << '"' - << ',' - // app - << '"' << "app" << '"' << ':' - << '"' << req->app << '"' - //<< ',' - << "}"; + ss << JOBJECT_START + << JFIELD_STR("action", "on_close") << JFIELD_CONT + << JFIELD_ORG("client_id", client_id) << JFIELD_CONT + << JFIELD_STR("ip", ip) << JFIELD_CONT + << JFIELD_STR("vhost", req->vhost) << JFIELD_CONT + << JFIELD_STR("app", req->app) << JFIELD_CONT + << JFIELD_STR("pageUrl", req->pageUrl) << JFIELD_CONT + << JOBJECT_END; std::string data = ss.str(); std::string res; @@ -340,32 +309,15 @@ int SrsHttpHooks::on_publish(std::string url, int client_id, std::string ip, Srs } */ std::stringstream ss; - ss << "{" - // action - << '"' << "action" << '"' << ':' - << '"' << "on_publish" << '"' - << ',' - // client_id - << '"' << "client_id" << '"' << ':' - << std::dec << client_id - << ',' - // ip - << '"' << "ip" << '"' << ':' - << '"' << ip << '"' - << ',' - // vhost - << '"' << "vhost" << '"' << ':' - << '"' << req->vhost << '"' - << ',' - // app - << '"' << "app" << '"' << ':' - << '"' << req->app << '"' - << ',' - // stream - << '"' << "stream" << '"' << ':' - << '"' << req->stream << '"' - //<< ',' - << "}"; + ss << JOBJECT_START + << JFIELD_STR("action", "on_publish") << JFIELD_CONT + << JFIELD_ORG("client_id", client_id) << JFIELD_CONT + << JFIELD_STR("ip", ip) << JFIELD_CONT + << JFIELD_STR("vhost", req->vhost) << JFIELD_CONT + << JFIELD_STR("app", req->app) << JFIELD_CONT + << JFIELD_STR("pageUrl", req->pageUrl) << JFIELD_CONT + << JFIELD_STR("stream", req->stream) << JFIELD_CONT + << JOBJECT_END; std::string data = ss.str(); std::string res; @@ -411,32 +363,15 @@ void SrsHttpHooks::on_unpublish(std::string url, int client_id, std::string ip, } */ std::stringstream ss; - ss << "{" - // action - << '"' << "action" << '"' << ':' - << '"' << "on_unpublish" << '"' - << ',' - // client_id - << '"' << "client_id" << '"' << ':' - << std::dec << client_id - << ',' - // ip - << '"' << "ip" << '"' << ':' - << '"' << ip << '"' - << ',' - // vhost - << '"' << "vhost" << '"' << ':' - << '"' << req->vhost << '"' - << ',' - // app - << '"' << "app" << '"' << ':' - << '"' << req->app << '"' - << ',' - // stream - << '"' << "stream" << '"' << ':' - << '"' << req->stream << '"' - //<< ',' - << "}"; + ss << JOBJECT_START + << JFIELD_STR("action", "on_unpublish") << JFIELD_CONT + << JFIELD_ORG("client_id", client_id) << JFIELD_CONT + << JFIELD_STR("ip", ip) << JFIELD_CONT + << JFIELD_STR("vhost", req->vhost) << JFIELD_CONT + << JFIELD_STR("app", req->app) << JFIELD_CONT + << JFIELD_STR("pageUrl", req->pageUrl) << JFIELD_CONT + << JFIELD_STR("stream", req->stream) << JFIELD_CONT + << JOBJECT_END; std::string data = ss.str(); std::string res; @@ -482,32 +417,15 @@ int SrsHttpHooks::on_play(std::string url, int client_id, std::string ip, SrsReq } */ std::stringstream ss; - ss << "{" - // action - << '"' << "action" << '"' << ':' - << '"' << "on_play" << '"' - << ',' - // client_id - << '"' << "client_id" << '"' << ':' - << std::dec << client_id - << ',' - // ip - << '"' << "ip" << '"' << ':' - << '"' << ip << '"' - << ',' - // vhost - << '"' << "vhost" << '"' << ':' - << '"' << req->vhost << '"' - << ',' - // app - << '"' << "app" << '"' << ':' - << '"' << req->app << '"' - << ',' - // stream - << '"' << "stream" << '"' << ':' - << '"' << req->stream << '"' - //<< ',' - << "}"; + ss << JOBJECT_START + << JFIELD_STR("action", "on_play") << JFIELD_CONT + << JFIELD_ORG("client_id", client_id) << JFIELD_CONT + << JFIELD_STR("ip", ip) << JFIELD_CONT + << JFIELD_STR("vhost", req->vhost) << JFIELD_CONT + << JFIELD_STR("app", req->app) << JFIELD_CONT + << JFIELD_STR("pageUrl", req->pageUrl) << JFIELD_CONT + << JFIELD_STR("stream", req->stream) << JFIELD_CONT + << JOBJECT_END; std::string data = ss.str(); std::string res; @@ -553,32 +471,15 @@ void SrsHttpHooks::on_stop(std::string url, int client_id, std::string ip, SrsRe } */ std::stringstream ss; - ss << "{" - // action - << '"' << "action" << '"' << ':' - << '"' << "on_stop" << '"' - << ',' - // client_id - << '"' << "client_id" << '"' << ':' - << std::dec << client_id - << ',' - // ip - << '"' << "ip" << '"' << ':' - << '"' << ip << '"' - << ',' - // vhost - << '"' << "vhost" << '"' << ':' - << '"' << req->vhost << '"' - << ',' - // app - << '"' << "app" << '"' << ':' - << '"' << req->app << '"' - << ',' - // stream - << '"' << "stream" << '"' << ':' - << '"' << req->stream << '"' - //<< ',' - << "}"; + ss << JOBJECT_START + << JFIELD_STR("action", "on_stop") << JFIELD_CONT + << JFIELD_ORG("client_id", client_id) << JFIELD_CONT + << JFIELD_STR("ip", ip) << JFIELD_CONT + << JFIELD_STR("vhost", req->vhost) << JFIELD_CONT + << JFIELD_STR("app", req->app) << JFIELD_CONT + << JFIELD_STR("pageUrl", req->pageUrl) << JFIELD_CONT + << JFIELD_STR("stream", req->stream) << JFIELD_CONT + << JOBJECT_END; std::string data = ss.str(); std::string res; diff --git a/trunk/src/app/srs_app_json.cpp b/trunk/src/app/srs_app_json.cpp new file mode 100644 index 000000000..f0859497e --- /dev/null +++ b/trunk/src/app/srs_app_json.cpp @@ -0,0 +1,24 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2014 winlin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include diff --git a/trunk/src/app/srs_app_json.hpp b/trunk/src/app/srs_app_json.hpp new file mode 100644 index 000000000..ef15847fa --- /dev/null +++ b/trunk/src/app/srs_app_json.hpp @@ -0,0 +1,40 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2014 winlin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef SRS_APP_JSON_HPP +#define SRS_APP_JSON_HPP + +/* +#include +*/ +#include + +// json encode macros +#define JOBJECT_START "{" +#define JFIELD_STR(k, v) "\"" << k << "\":\"" << v << "\"" +#define JFIELD_ORG(k, v) "\"" << k << "\":" << std::dec << v +#define JFIELD_ERROR(ret) "\"" << "code" << "\":" << ret +#define JFIELD_CONT "," +#define JOBJECT_END "}" + +#endif \ No newline at end of file diff --git a/trunk/src/srs/srs.upp b/trunk/src/srs/srs.upp index e96552ac0..dcd388162 100755 --- a/trunk/src/srs/srs.upp +++ b/trunk/src/srs/srs.upp @@ -61,6 +61,8 @@ file ..\app\srs_app_http_conn.cpp, ..\app\srs_app_http_hooks.hpp, ..\app\srs_app_http_hooks.cpp, + ..\app\srs_app_json.hpp, + ..\app\srs_app_json.cpp, ..\app\srs_app_log.hpp, ..\app\srs_app_log.cpp, ..\app\srs_app_refer.hpp,