From 6e5143449ed8e9a4296ab47eca392867af24ac1e Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 22 Aug 2015 18:18:18 +0800 Subject: [PATCH] HTTP API support JSONP by specifies the query string callback=xxx. --- README.md | 1 + trunk/src/app/srs_app_http_api.cpp | 171 ++++++++++++++++++++------ trunk/src/app/srs_app_http_conn.cpp | 5 + trunk/src/app/srs_app_http_conn.hpp | 1 + trunk/src/protocol/srs_http_stack.cpp | 35 ++---- trunk/src/protocol/srs_http_stack.hpp | 9 +- 6 files changed, 148 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index 3c89f899e..880e54452 100755 --- a/README.md +++ b/README.md @@ -342,6 +342,7 @@ Remark: ## History +* v2.0, 2015-08-22, HTTP API support JSONP by specifies the query string callback=xxx. * v2.0, 2015-08-20, fix [#380](https://github.com/simple-rtmp-server/srs/issues/380), srs-librtmp send sequence header when sps or pps changed. * v2.0, 2015-08-18, close [#454](https://github.com/simple-rtmp-server/srs/issues/454), support obs restart publish. 2.0.184 * v2.0, 2015-08-14, use reduce_sequence_header for stream control. diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 46e862ab9..46d94a94c 100755 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -43,6 +43,95 @@ using namespace std; #include #include +int srs_api_response_jsonp(ISrsHttpResponseWriter* w, string callback, string data) +{ + int ret = ERROR_SUCCESS; + + SrsHttpHeader* h = w->header(); + + h->set_content_length(data.length() + callback.length() + 2); + h->set_content_type("text/javascript"); + + if (!callback.empty() && (ret = w->write((char*)callback.data(), (int)callback.length())) != ERROR_SUCCESS) { + return ret; + } + + static char* c0 = (char*)"("; + if ((ret = w->write(c0, 1)) != ERROR_SUCCESS) { + return ret; + } + if ((ret = w->write((char*)data.data(), (int)data.length())) != ERROR_SUCCESS) { + return ret; + } + + static char* c1 = (char*)")"; + if ((ret = w->write(c1, 1)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int srs_api_response_jsonp_code(ISrsHttpResponseWriter* w, string callback, int code) +{ + std::stringstream ss; + + ss << SRS_JOBJECT_START + << SRS_JFIELD_ERROR(code) + << SRS_JOBJECT_END; + + return srs_api_response_jsonp(w, callback, ss.str()); +} + +int srs_api_response_json(ISrsHttpResponseWriter* w, string data) +{ + SrsHttpHeader* h = w->header(); + + h->set_content_length(data.length()); + h->set_content_type("application/json"); + + return w->write((char*)data.data(), (int)data.length()); +} + +int srs_api_response_json_code(ISrsHttpResponseWriter* w, int code) +{ + std::stringstream ss; + + ss << SRS_JOBJECT_START + << SRS_JFIELD_ERROR(code) + << SRS_JOBJECT_END; + + return srs_api_response_json(w, ss.str()); +} + +int srs_api_response(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string json) +{ + string callback = r->query_get("callback"); + bool jsonp = !callback.empty(); + + // no jsonp, directly response. + if (!jsonp) { + return srs_api_response_json(w, json); + } + + // jsonp, get function name from query("callback") + return srs_api_response_jsonp(w, callback, json); +} + +int srs_api_response_code(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, int code) +{ + string callback = r->query_get("callback"); + bool jsonp = !callback.empty(); + + // no jsonp, directly response. + if (!jsonp) { + return srs_api_response_json_code(w, code); + } + + // jsonp, get function name from query("callback") + return srs_api_response_jsonp_code(w, callback, code); +} + SrsGoApiRoot::SrsGoApiRoot() { } @@ -64,7 +153,7 @@ int SrsGoApiRoot::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) << SRS_JOBJECT_END << SRS_JOBJECT_END; - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiApi::SrsGoApiApi() @@ -88,7 +177,7 @@ int SrsGoApiApi::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) << SRS_JOBJECT_END << SRS_JOBJECT_END; - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiV1::SrsGoApiV1() @@ -129,7 +218,7 @@ int SrsGoApiV1::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) << SRS_JOBJECT_END << SRS_JOBJECT_END; - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiVersion::SrsGoApiVersion() @@ -156,7 +245,7 @@ int SrsGoApiVersion::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) << SRS_JOBJECT_END << SRS_JOBJECT_END; - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiSummaries::SrsGoApiSummaries() @@ -171,7 +260,7 @@ int SrsGoApiSummaries::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) { std::stringstream ss; srs_api_dump_summaries(ss); - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiRusages::SrsGoApiRusages() @@ -182,39 +271,39 @@ SrsGoApiRusages::~SrsGoApiRusages() { } -int SrsGoApiRusages::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* req) +int SrsGoApiRusages::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) { SrsStatistic* stat = SrsStatistic::instance(); std::stringstream ss; - SrsRusage* r = srs_get_system_rusage(); + SrsRusage* ru = srs_get_system_rusage(); ss << SRS_JOBJECT_START << SRS_JFIELD_ERROR(ERROR_SUCCESS) << SRS_JFIELD_CONT << SRS_JFIELD_ORG("server", stat->server_id()) << SRS_JFIELD_CONT << SRS_JFIELD_ORG("data", SRS_JOBJECT_START) - << SRS_JFIELD_ORG("ok", (r->ok? "true":"false")) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("sample_time", r->sample_time) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_utime", r->r.ru_utime.tv_sec) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_stime", r->r.ru_stime.tv_sec) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_maxrss", r->r.ru_maxrss) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_ixrss", r->r.ru_ixrss) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_idrss", r->r.ru_idrss) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_isrss", r->r.ru_isrss) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_minflt", r->r.ru_minflt) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_majflt", r->r.ru_majflt) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_nswap", r->r.ru_nswap) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_inblock", r->r.ru_inblock) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_oublock", r->r.ru_oublock) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_msgsnd", r->r.ru_msgsnd) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_msgrcv", r->r.ru_msgrcv) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_nsignals", r->r.ru_nsignals) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_nvcsw", r->r.ru_nvcsw) << SRS_JFIELD_CONT - << SRS_JFIELD_ORG("ru_nivcsw", r->r.ru_nivcsw) + << SRS_JFIELD_ORG("ok", (ru->ok? "true":"false")) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("sample_time", ru->sample_time) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_utime", ru->r.ru_utime.tv_sec) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_stime", ru->r.ru_stime.tv_sec) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_maxrss", ru->r.ru_maxrss) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_ixrss", ru->r.ru_ixrss) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_idrss", ru->r.ru_idrss) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_isrss", ru->r.ru_isrss) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_minflt", ru->r.ru_minflt) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_majflt", ru->r.ru_majflt) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_nswap", ru->r.ru_nswap) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_inblock", ru->r.ru_inblock) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_oublock", ru->r.ru_oublock) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_msgsnd", ru->r.ru_msgsnd) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_msgrcv", ru->r.ru_msgrcv) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_nsignals", ru->r.ru_nsignals) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_nvcsw", ru->r.ru_nvcsw) << SRS_JFIELD_CONT + << SRS_JFIELD_ORG("ru_nivcsw", ru->r.ru_nivcsw) << SRS_JOBJECT_END << SRS_JOBJECT_END; - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiSelfProcStats::SrsGoApiSelfProcStats() @@ -286,7 +375,7 @@ int SrsGoApiSelfProcStats::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage << SRS_JOBJECT_END << SRS_JOBJECT_END; - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiSystemProcStats::SrsGoApiSystemProcStats() @@ -323,7 +412,7 @@ int SrsGoApiSystemProcStats::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa << SRS_JOBJECT_END << SRS_JOBJECT_END; - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiMemInfos::SrsGoApiMemInfos() @@ -361,7 +450,7 @@ int SrsGoApiMemInfos::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) << SRS_JOBJECT_END << SRS_JOBJECT_END; - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiAuthors::SrsGoApiAuthors() @@ -390,7 +479,7 @@ int SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) << SRS_JOBJECT_END << SRS_JOBJECT_END; - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiFeatures::SrsGoApiFeatures() @@ -516,7 +605,7 @@ int SrsGoApiFeatures::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) << SRS_JOBJECT_END << SRS_JOBJECT_END; - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiRequests::SrsGoApiRequests() @@ -579,7 +668,7 @@ int SrsGoApiRequests::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) << SRS_JOBJECT_END << SRS_JOBJECT_END; - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiVhosts::SrsGoApiVhosts() @@ -605,7 +694,7 @@ int SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) if (vid > 0 && (vhost = stat->find_vhost(vid)) == NULL) { ret = ERROR_RTMP_STREAM_NOT_FOUND; srs_error("vhost id=%d not found. ret=%d", vid, ret); - return srs_http_response_code(w, ret); + return srs_api_response_code(w, r, ret); } if (r->is_http_get()) { @@ -629,10 +718,10 @@ int SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) << SRS_JOBJECT_END; } - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } SrsGoApiStreams::SrsGoApiStreams() @@ -658,7 +747,7 @@ int SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) if (sid >= 0 && (stream = stat->find_stream(sid)) == NULL) { ret = ERROR_RTMP_STREAM_NOT_FOUND; srs_error("stream stream_id=%d not found. ret=%d", sid, ret); - return srs_http_response_code(w, ret); + return srs_api_response_code(w, r, ret); } if (r->is_http_get()) { @@ -682,7 +771,7 @@ int SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) << SRS_JOBJECT_END; } - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } return ret; @@ -711,7 +800,7 @@ int SrsGoApiClients::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) if (cid >= 0 && (client = stat->find_client(cid)) == NULL) { ret = ERROR_RTMP_STREAM_NOT_FOUND; srs_error("stream client_id=%d not found. ret=%d", cid, ret); - return srs_http_response_code(w, ret); + return srs_api_response_code(w, r, ret); } if (r->is_http_delete()) { @@ -719,7 +808,7 @@ int SrsGoApiClients::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) client->conn->expire(); srs_warn("delete client=%d ok", cid); - return srs_http_response_code(w, ret); + return srs_api_response_code(w, r, ret); } else if (r->is_http_get()) { std::stringstream data; @@ -741,7 +830,7 @@ int SrsGoApiClients::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) << SRS_JOBJECT_END; } - return srs_http_response_json(w, ss.str()); + return srs_api_response(w, r, ss.str()); } else { return srs_go_http_error(w, SRS_CONSTS_HTTP_MethodNotAllowed); } @@ -759,7 +848,7 @@ SrsGoApiError::~SrsGoApiError() int SrsGoApiError::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) { - return srs_http_response_code(w, 100); + return srs_api_response_code(w, r, 100); } diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index b74830eeb..a18190a60 100755 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -673,6 +673,11 @@ string SrsHttpMessage::path() return _uri->get_path(); } +string SrsHttpMessage::query() +{ + return _uri->get_query(); +} + string SrsHttpMessage::ext() { return _ext; diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index 731a00b6f..1396f7671 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -245,6 +245,7 @@ public: virtual std::string url(); virtual std::string host(); virtual std::string path(); + virtual std::string query(); virtual std::string ext(); /** * get the RESTful matched id. diff --git a/trunk/src/protocol/srs_http_stack.cpp b/trunk/src/protocol/srs_http_stack.cpp index 8f767279b..33f89e7af 100755 --- a/trunk/src/protocol/srs_http_stack.cpp +++ b/trunk/src/protocol/srs_http_stack.cpp @@ -137,27 +137,6 @@ int srs_go_http_error(ISrsHttpResponseWriter* w, int code, string error) return ret; } -int srs_http_response_json(ISrsHttpResponseWriter* w, string data) -{ - SrsHttpHeader* h = w->header(); - - h->set_content_length(data.length()); - h->set_content_type("application/json"); - - return w->write((char*)data.data(), (int)data.length()); -} - -int srs_http_response_code(ISrsHttpResponseWriter* w, int code) -{ - std::stringstream ss; - - ss << SRS_JOBJECT_START - << SRS_JFIELD_ERROR(code) - << SRS_JOBJECT_END; - - return srs_http_response_json(w, ss.str()); -} - SrsHttpHeader::SrsHttpHeader() { } @@ -261,17 +240,23 @@ SrsHttpRedirectHandler::~SrsHttpRedirectHandler() int SrsHttpRedirectHandler::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) { int ret = ERROR_SUCCESS; - string msg = "Moved Permsanently"; + + string location = url; + if (!r->query().empty()) { + location += "?" + r->query(); + } + + string msg = "Redirect to" + location; w->header()->set_content_type("text/plain; charset=utf-8"); w->header()->set_content_length(msg.length()); - w->header()->set("Location", url); + w->header()->set("Location", location); w->write_header(code); w->write((char*)msg.data(), (int)msg.length()); w->final_request(); - srs_info("redirect to %s.", url.c_str()); + srs_info("redirect to %s.", location.c_str()); return ret; } @@ -636,7 +621,7 @@ int SrsHttpServeMux::handle(std::string pattern, ISrsHttpHandler* handler) entry = new SrsHttpMuxEntry(); entry->explicit_match = false; - entry->handler = new SrsHttpRedirectHandler(pattern, SRS_CONSTS_HTTP_MovedPermanently); + entry->handler = new SrsHttpRedirectHandler(pattern, SRS_CONSTS_HTTP_Found); entry->pattern = pattern; entry->handler->entry = entry; diff --git a/trunk/src/protocol/srs_http_stack.hpp b/trunk/src/protocol/srs_http_stack.hpp index 4e4fed7a2..ff59172d6 100644 --- a/trunk/src/protocol/srs_http_stack.hpp +++ b/trunk/src/protocol/srs_http_stack.hpp @@ -81,14 +81,6 @@ class ISrsHttpResponseWriter; extern int srs_go_http_error(ISrsHttpResponseWriter* w, int code); extern int srs_go_http_error(ISrsHttpResponseWriter* w, int code, std::string error); -// helper function: response in json format. -extern int srs_http_response_json(ISrsHttpResponseWriter* w, std::string data); -/** - * response a typical code object, for example: - * {code : 100} - */ -extern int srs_http_response_code(ISrsHttpResponseWriter* w, int code); - // get the status text of code. extern std::string srs_generate_http_status_text(int status); @@ -497,6 +489,7 @@ public: virtual std::string url() = 0; virtual std::string host() = 0; virtual std::string path() = 0; + virtual std::string query() = 0; virtual std::string ext() = 0; /** * get the RESTful id,