SrsHttpApi类
app/srs_app_http_api.hpp
app/srs_app_http_api.cpp
class SrsHttpApi : virtual public SrsConnection, virtual public ISrsReloadHandler { private: SrsHttpParser* parser; SrsHttpCorsMux* cors; SrsHttpServeMux* mux; public: SrsHttpApi(IConnectionManager* cm, st_netfd_t fd, SrsHttpServeMux* m, std::string cip); virtual ~SrsHttpApi(); // interface IKbpsDelta public: virtual void resample(); virtual int64_t get_send_bytes_delta(); virtual int64_t get_recv_bytes_delta(); virtual void cleanup(); protected: virtual int do_cycle(); private: virtual int process_request(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); // interface ISrsReloadHandler public: virtual int on_reload_http_api_crossdomain(); };
int SrsHttpApi::do_cycle() { int ret = ERROR_SUCCESS; srs_trace("api get peer ip success. ip=%s", ip.c_str()); // initialize parser if ((ret = parser->initialize(HTTP_REQUEST, true)) != ERROR_SUCCESS) { srs_error("api initialize http parser failed. ret=%d", ret); return ret; } // set the recv timeout, for some clients never disconnect the connection. // @see https://github.com/ossrs/srs/issues/398 skt->set_recv_timeout(SRS_HTTP_RECV_TMMS); // initialize the cors, which will proxy to mux. bool crossdomain_enabled = _srs_config->get_http_api_crossdomain(); if ((ret = cors->initialize(mux, crossdomain_enabled)) != ERROR_SUCCESS) { return ret; } // process http messages. while(!disposed) { ISrsHttpMessage* req = NULL; // get a http message if ((ret = parser->parse_message(skt, this, &req)) != ERROR_SUCCESS) { return ret; } // if SUCCESS, always NOT-NULL. srs_assert(req); // always free it in this scope. SrsAutoFree(ISrsHttpMessage, req); // ok, handle http request. SrsHttpResponseWriter writer(skt); if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) { return ret; } // read all rest bytes in request body. char buf[SRS_HTTP_READ_CACHE_BYTES]; ISrsHttpResponseReader* br = req->body_reader(); while (!br->eof()) { if ((ret = br->read(buf, SRS_HTTP_READ_CACHE_BYTES, NULL)) != ERROR_SUCCESS) { return ret; } } // donot keep alive, disconnect it. // @see https://github.com/ossrs/srs/issues/399 if (!req->is_keep_alive()) { break; } } return ret; }
1. call SrsHttpParser::parse_message(skt, this, &req)得到 ISrsHttpMessage类型的 req
2. SrsHttpResponseWriter writer(skt); process_request(&writer, req)
int SrsHttpParser::parse_message(ISrsProtocolReaderWriter* io, SrsConnection* conn, ISrsHttpMessage** ppmsg) { *ppmsg = NULL; int ret = ERROR_SUCCESS; // reset request data. field_name = ""; field_value = ""; expect_field_name = true; state = SrsHttpParseStateInit; header = http_parser(); url = ""; headers.clear(); header_parsed = 0; // do parse if ((ret = parse_message_imp(io)) != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret)) { srs_error("parse http msg failed. ret=%d", ret); } return ret; } // create msg SrsHttpMessage* msg = new SrsHttpMessage(io, conn); // initalize http msg, parse url. if ((ret = msg->update(url, jsonp, &header, buffer, headers)) != ERROR_SUCCESS) { srs_error("initialize http msg failed. ret=%d", ret); srs_freep(msg); return ret; } // parse ok, return the msg. *ppmsg = msg; return ret; }
int SrsHttpParser::parse_message_imp(ISrsProtocolReaderWriter* io) { int ret = ERROR_SUCCESS; while (true) { ssize_t nparsed = 0; // when got entire http header, parse it. // @see https://github.com/ossrs/srs/issues/400 char* start = buffer->bytes(); char* end = start + buffer->size(); for (char* p = start; p <= end - 4; p++) { // SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A if (p[0] == SRS_CONSTS_CR && p[1] == SRS_CONSTS_LF && p[2] == SRS_CONSTS_CR && p[3] == SRS_CONSTS_LF) { nparsed = http_parser_execute(&parser, &settings, buffer->bytes(), buffer->size()); srs_info("buffer=%d, nparsed=%d, header=%d", buffer->size(), (int)nparsed, header_parsed); break; } } // consume the parsed bytes. if (nparsed && header_parsed) { buffer->read_slice(header_parsed); } // ok atleast header completed, // never wait for body completed, for maybe chunked. if (state == SrsHttpParseStateHeaderComplete || state == SrsHttpParseStateMessageComplete) { break; } // when nothing parsed, read more to parse. if (nparsed == 0) { // when requires more, only grow 1bytes, but the buffer will cache more. if ((ret = buffer->grow(io, buffer->size() + 1)) != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret)) { srs_error("read body from server failed. ret=%d", ret); } return ret; } } } // parse last header. if (!field_name.empty() && !field_value.empty()) { headers.push_back(std::make_pair(field_name, field_value)); } return ret; }
1. parse_message_imp函数里调用
http_parser_execute(&parser, &settings, buffer->bytes(), buffer->size());执行http parser
在此过程中会回调 settings中的函数保存此次解析的结果
parse_message_imp函数解析的是http头部的数据
2. msg->update(url, jsonp, &header, buffer, headers))
int SrsHttpMessage::update(string url, bool allow_jsonp, http_parser* header, SrsFastStream* body, vector<SrsHttpHeaderField>& headers) { int ret = ERROR_SUCCESS; _url = url; _header = *header; _headers = headers; // whether chunked. std::string transfer_encoding = get_request_header("Transfer-Encoding"); chunked = (transfer_encoding == "chunked"); // whether keep alive. keep_alive = http_should_keep_alive(header); // set the buffer. if ((ret = _body->initialize(body)) != ERROR_SUCCESS) { return ret; } // parse uri from url. std::string host = get_request_header("Host"); // use server public ip when no host specified. // to make telnet happy. if (host.empty()) { host= srs_get_public_internet_address(); } // parse uri to schema/server:port/path?query std::string uri = "http://" + host + _url; if ((ret = _uri->initialize(uri)) != ERROR_SUCCESS) { return ret; } // parse ext. _ext = srs_path_filext(_uri->get_path()); // parse query string. srs_parse_query_string(_uri->get_query(), _query); // parse jsonp request message. if (allow_jsonp) { if (!query_get("callback").empty()) { jsonp = true; } if (jsonp) { jsonp_method = query_get("method"); } } return ret; }
int SrsHttpApi::process_request(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) { int ret = ERROR_SUCCESS; SrsHttpMessage* hm = dynamic_cast<SrsHttpMessage*>(r); srs_assert(hm); srs_trace("HTTP API %s %s, content-length=%" PRId64 ", chunked=%d/%d", r->method_str().c_str(), r->url().c_str(), r->content_length(), hm->is_chunked(), hm->is_infinite_chunked()); // use cors server mux to serve http request, which will proxy to mux. if ((ret = cors->serve_http(w, r)) != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret)) { srs_error("serve http msg failed. ret=%d", ret); } return ret; } return ret; }
在 SrsServer:: fd2conn中看到
conn = new SrsHttpApi(this, stfd, http_api_mux, ip);
所以请求会有
http_api_mux变量处理,
http_api_mux的请求路由设置是在SrsServer::http_handle函数,调用位置 srs_main_server.cpp:434 run_master函数
[zk2013@localhost src]$ grep -Fnr "http_handle" app/srs_app_server.cpp:752:int SrsServer::http_handle() app/srs_app_server.hpp:290: virtual int http_handle(); main/srs_main_server.cpp:434: if ((ret = svr->http_handle()) != ERROR_SUCCESS) {
int run_master(SrsServer* svr) { int ret = ERROR_SUCCESS; if ((ret = svr->initialize_st()) != ERROR_SUCCESS) { return ret; } if ((ret = svr->initialize_signal()) != ERROR_SUCCESS) { return ret; } if ((ret = svr->acquire_pid_file()) != ERROR_SUCCESS) { return ret; } // 开启 rtmp, http, caster 监听 if ((ret = svr->listen()) != ERROR_SUCCESS) { return ret; } if ((ret = svr->register_signal()) != ERROR_SUCCESS) { return ret; } // 设置 http api的路由处理 if ((ret = svr->http_handle()) != ERROR_SUCCESS) { return ret; } if ((ret = svr->ingest()) != ERROR_SUCCESS) { return ret; } if ((ret = svr->cycle()) != ERROR_SUCCESS) { return ret; } return 0; }
int SrsServer::http_handle() { int ret = ERROR_SUCCESS; srs_assert(http_api_mux); if ((ret = http_api_mux->handle("/", new SrsHttpNotFoundHandler())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/", new SrsGoApiApi())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/", new SrsGoApiV1())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/versions", new SrsGoApiVersion())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/summaries", new SrsGoApiSummaries())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/rusages", new SrsGoApiRusages())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/self_proc_stats", new SrsGoApiSelfProcStats())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/system_proc_stats", new SrsGoApiSystemProcStats())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/meminfos", new SrsGoApiMemInfos())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/authors", new SrsGoApiAuthors())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/features", new SrsGoApiFeatures())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/vhosts/", new SrsGoApiVhosts())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/streams/", new SrsGoApiStreams())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/clients/", new SrsGoApiClients())) != ERROR_SUCCESS) { return ret; } if ((ret = http_api_mux->handle("/api/v1/raw", new SrsGoApiRaw(this))) != ERROR_SUCCESS) { return ret; } // test the request info. if ((ret = http_api_mux->handle("/api/v1/tests/requests", new SrsGoApiRequests())) != ERROR_SUCCESS) { return ret; } // test the error code response. if ((ret = http_api_mux->handle("/api/v1/tests/errors", new SrsGoApiError())) != ERROR_SUCCESS) { return ret; } // test the redirect mechenism. if ((ret = http_api_mux->handle("/api/v1/tests/redirects", new SrsHttpRedirectHandler("/api/v1/tests/errors", SRS_CONSTS_HTTP_MovedPermanently))) != ERROR_SUCCESS) { return ret; } // test the http vhost. if ((ret = http_api_mux->handle("error.srs.com/api/v1/tests/errors", new SrsGoApiError())) != ERROR_SUCCESS) { return ret; } // TODO: FIXME: for console. // TODO: FIXME: support reload. std::string dir = _srs_config->get_http_stream_dir() + "/console"; if ((ret = http_api_mux->handle("/console/", new SrsHttpFileServer(dir))) != ERROR_SUCCESS) { srs_error("http: mount console dir=%s failed. ret=%d", dir.c_str(), ret); return ret; } srs_trace("http: api mount /console to %s", dir.c_str()); return ret; }