mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
refine code, extrat the ISrsHttpMessage.
This commit is contained in:
parent
e2955da78f
commit
ce1bb6c605
13 changed files with 1323 additions and 1202 deletions
|
@ -82,14 +82,14 @@ void SrsHttpHeartbeat::heartbeat()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpMessage* msg = NULL;
|
ISrsHttpMessage* msg = NULL;
|
||||||
if ((ret = http.post(uri.get_path(), req, &msg)) != ERROR_SUCCESS) {
|
if ((ret = http.post(uri.get_path(), req, &msg)) != ERROR_SUCCESS) {
|
||||||
srs_info("http post hartbeart uri failed. "
|
srs_info("http post hartbeart uri failed. "
|
||||||
"url=%s, request=%s, response=%s, ret=%d",
|
"url=%s, request=%s, response=%s, ret=%d",
|
||||||
url.c_str(), req.c_str(), res.c_str(), ret);
|
url.c_str(), req.c_str(), res.c_str(), ret);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SrsAutoFree(SrsHttpMessage, msg);
|
SrsAutoFree(ISrsHttpMessage, msg);
|
||||||
|
|
||||||
std::string res;
|
std::string res;
|
||||||
if ((ret = msg->body_read_all(res)) != ERROR_SUCCESS) {
|
if ((ret = msg->body_read_all(res)) != ERROR_SUCCESS) {
|
||||||
|
|
|
@ -25,726 +25,17 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
#ifdef SRS_AUTO_HTTP_PARSER
|
#ifdef SRS_AUTO_HTTP_PARSER
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <sstream>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <algorithm>
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#include <srs_kernel_error.hpp>
|
#include <srs_kernel_error.hpp>
|
||||||
#include <srs_kernel_log.hpp>
|
#include <srs_kernel_log.hpp>
|
||||||
#include <srs_app_st_socket.hpp>
|
#include <srs_app_st_socket.hpp>
|
||||||
#include <srs_app_http_api.hpp>
|
|
||||||
#include <srs_app_http_conn.hpp>
|
|
||||||
#include <srs_app_json.hpp>
|
|
||||||
#include <srs_kernel_utility.hpp>
|
|
||||||
#include <srs_rtmp_buffer.hpp>
|
|
||||||
#include <srs_kernel_file.hpp>
|
|
||||||
#include <srs_core_autofree.hpp>
|
|
||||||
#include <srs_rtmp_buffer.hpp>
|
|
||||||
#include <srs_rtmp_sdk.hpp>
|
#include <srs_rtmp_sdk.hpp>
|
||||||
|
#include <srs_rtmp_buffer.hpp>
|
||||||
|
#include <srs_kernel_utility.hpp>
|
||||||
#include <srs_rtmp_utility.hpp>
|
#include <srs_rtmp_utility.hpp>
|
||||||
|
#include <srs_core_autofree.hpp>
|
||||||
#define SRS_DEFAULT_HTTP_PORT 80
|
|
||||||
|
|
||||||
// for http parser macros
|
|
||||||
#define SRS_CONSTS_HTTP_OPTIONS HTTP_OPTIONS
|
|
||||||
#define SRS_CONSTS_HTTP_GET HTTP_GET
|
|
||||||
#define SRS_CONSTS_HTTP_POST HTTP_POST
|
|
||||||
#define SRS_CONSTS_HTTP_PUT HTTP_PUT
|
|
||||||
#define SRS_CONSTS_HTTP_DELETE HTTP_DELETE
|
|
||||||
|
|
||||||
// for ead all of http body, read each time.
|
|
||||||
#define SRS_HTTP_READ_CACHE_BYTES 4096
|
|
||||||
|
|
||||||
#define SRS_HTTP_DEFAULT_PAGE "index.html"
|
|
||||||
|
|
||||||
int srs_http_response_json(ISrsHttpResponseWriter* w, string data)
|
|
||||||
{
|
|
||||||
w->header()->set_content_length(data.length());
|
|
||||||
w->header()->set_content_type("application/json");
|
|
||||||
|
|
||||||
return w->write((char*)data.data(), (int)data.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the status text of code.
|
|
||||||
string srs_generate_http_status_text(int status)
|
|
||||||
{
|
|
||||||
static std::map<int, std::string> _status_map;
|
|
||||||
if (_status_map.empty()) {
|
|
||||||
_status_map[SRS_CONSTS_HTTP_Continue ] = SRS_CONSTS_HTTP_Continue_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_SwitchingProtocols ] = SRS_CONSTS_HTTP_SwitchingProtocols_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_OK ] = SRS_CONSTS_HTTP_OK_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_Created ] = SRS_CONSTS_HTTP_Created_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_Accepted ] = SRS_CONSTS_HTTP_Accepted_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_NonAuthoritativeInformation ] = SRS_CONSTS_HTTP_NonAuthoritativeInformation_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_NoContent ] = SRS_CONSTS_HTTP_NoContent_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_ResetContent ] = SRS_CONSTS_HTTP_ResetContent_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_PartialContent ] = SRS_CONSTS_HTTP_PartialContent_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_MultipleChoices ] = SRS_CONSTS_HTTP_MultipleChoices_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_MovedPermanently ] = SRS_CONSTS_HTTP_MovedPermanently_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_Found ] = SRS_CONSTS_HTTP_Found_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_SeeOther ] = SRS_CONSTS_HTTP_SeeOther_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_NotModified ] = SRS_CONSTS_HTTP_NotModified_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_UseProxy ] = SRS_CONSTS_HTTP_UseProxy_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_TemporaryRedirect ] = SRS_CONSTS_HTTP_TemporaryRedirect_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_BadRequest ] = SRS_CONSTS_HTTP_BadRequest_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_Unauthorized ] = SRS_CONSTS_HTTP_Unauthorized_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_PaymentRequired ] = SRS_CONSTS_HTTP_PaymentRequired_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_Forbidden ] = SRS_CONSTS_HTTP_Forbidden_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_NotFound ] = SRS_CONSTS_HTTP_NotFound_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_MethodNotAllowed ] = SRS_CONSTS_HTTP_MethodNotAllowed_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_NotAcceptable ] = SRS_CONSTS_HTTP_NotAcceptable_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_ProxyAuthenticationRequired ] = SRS_CONSTS_HTTP_ProxyAuthenticationRequired_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_RequestTimeout ] = SRS_CONSTS_HTTP_RequestTimeout_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_Conflict ] = SRS_CONSTS_HTTP_Conflict_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_Gone ] = SRS_CONSTS_HTTP_Gone_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_LengthRequired ] = SRS_CONSTS_HTTP_LengthRequired_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_PreconditionFailed ] = SRS_CONSTS_HTTP_PreconditionFailed_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_RequestEntityTooLarge ] = SRS_CONSTS_HTTP_RequestEntityTooLarge_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_RequestURITooLarge ] = SRS_CONSTS_HTTP_RequestURITooLarge_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_UnsupportedMediaType ] = SRS_CONSTS_HTTP_UnsupportedMediaType_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_RequestedRangeNotSatisfiable ] = SRS_CONSTS_HTTP_RequestedRangeNotSatisfiable_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_ExpectationFailed ] = SRS_CONSTS_HTTP_ExpectationFailed_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_InternalServerError ] = SRS_CONSTS_HTTP_InternalServerError_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_NotImplemented ] = SRS_CONSTS_HTTP_NotImplemented_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_BadGateway ] = SRS_CONSTS_HTTP_BadGateway_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_ServiceUnavailable ] = SRS_CONSTS_HTTP_ServiceUnavailable_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_GatewayTimeout ] = SRS_CONSTS_HTTP_GatewayTimeout_str ;
|
|
||||||
_status_map[SRS_CONSTS_HTTP_HTTPVersionNotSupported ] = SRS_CONSTS_HTTP_HTTPVersionNotSupported_str ;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string status_text;
|
|
||||||
if (_status_map.find(status) == _status_map.end()) {
|
|
||||||
status_text = "Status Unknown";
|
|
||||||
} else {
|
|
||||||
status_text = _status_map[status];
|
|
||||||
}
|
|
||||||
|
|
||||||
return status_text;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bodyAllowedForStatus reports whether a given response status code
|
|
||||||
// permits a body. See RFC2616, section 4.4.
|
|
||||||
bool srs_go_http_body_allowd(int status)
|
|
||||||
{
|
|
||||||
if (status >= 100 && status <= 199) {
|
|
||||||
return false;
|
|
||||||
} else if (status == 204 || status == 304) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DetectContentType implements the algorithm described
|
|
||||||
// at http://mimesniff.spec.whatwg.org/ to determine the
|
|
||||||
// Content-Type of the given data. It considers at most the
|
|
||||||
// first 512 bytes of data. DetectContentType always returns
|
|
||||||
// a valid MIME type: if it cannot determine a more specific one, it
|
|
||||||
// returns "application/octet-stream".
|
|
||||||
string srs_go_http_detect(char* data, int size)
|
|
||||||
{
|
|
||||||
// detect only when data specified.
|
|
||||||
if (data) {
|
|
||||||
}
|
|
||||||
return "application/octet-stream"; // fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error replies to the request with the specified error message and HTTP code.
|
|
||||||
// The error message should be plain text.
|
|
||||||
int srs_go_http_error(ISrsHttpResponseWriter* w, int code, string error)
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
w->header()->set_content_type("text/plain; charset=utf-8");
|
|
||||||
w->header()->set_content_length(error.length());
|
|
||||||
w->write_header(code);
|
|
||||||
w->write((char*)error.data(), (int)error.length());
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpHeader::SrsHttpHeader()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpHeader::~SrsHttpHeader()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SrsHttpHeader::set(string key, string value)
|
|
||||||
{
|
|
||||||
headers[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
string SrsHttpHeader::get(string key)
|
|
||||||
{
|
|
||||||
std::string v;
|
|
||||||
|
|
||||||
if (headers.find(key) != headers.end()) {
|
|
||||||
v = headers[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t SrsHttpHeader::content_length()
|
|
||||||
{
|
|
||||||
std::string cl = get("Content-Length");
|
|
||||||
|
|
||||||
if (cl.empty()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int64_t)::atof(cl.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SrsHttpHeader::set_content_length(int64_t size)
|
|
||||||
{
|
|
||||||
char buf[64];
|
|
||||||
snprintf(buf, sizeof(buf), "%"PRId64, size);
|
|
||||||
set("Content-Length", buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
string SrsHttpHeader::content_type()
|
|
||||||
{
|
|
||||||
return get("Content-Type");
|
|
||||||
}
|
|
||||||
|
|
||||||
void SrsHttpHeader::set_content_type(string ct)
|
|
||||||
{
|
|
||||||
set("Content-Type", ct);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SrsHttpHeader::write(stringstream& ss)
|
|
||||||
{
|
|
||||||
std::map<std::string, std::string>::iterator it;
|
|
||||||
for (it = headers.begin(); it != headers.end(); ++it) {
|
|
||||||
ss << it->first << ": " << it->second << SRS_HTTP_CRLF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ISrsHttpResponseWriter::ISrsHttpResponseWriter()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ISrsHttpResponseWriter::~ISrsHttpResponseWriter()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ISrsHttpResponseReader::ISrsHttpResponseReader()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ISrsHttpResponseReader::~ISrsHttpResponseReader()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ISrsHttpHandler::ISrsHttpHandler()
|
|
||||||
{
|
|
||||||
entry = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ISrsHttpHandler::~ISrsHttpHandler()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpRedirectHandler::SrsHttpRedirectHandler(string u, int c)
|
|
||||||
{
|
|
||||||
url = u;
|
|
||||||
code = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpRedirectHandler::~SrsHttpRedirectHandler()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpRedirectHandler::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
// TODO: FIXME: implements it.
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpNotFoundHandler::SrsHttpNotFoundHandler()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpNotFoundHandler::~SrsHttpNotFoundHandler()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpNotFoundHandler::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|
||||||
{
|
|
||||||
return srs_go_http_error(w,
|
|
||||||
SRS_CONSTS_HTTP_NotFound, SRS_CONSTS_HTTP_NotFound_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpFileServer::SrsHttpFileServer(string root_dir)
|
|
||||||
{
|
|
||||||
dir = root_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpFileServer::~SrsHttpFileServer()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpFileServer::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|
||||||
{
|
|
||||||
string upath = r->path();
|
|
||||||
|
|
||||||
// add default pages.
|
|
||||||
if (srs_string_ends_with(upath, "/")) {
|
|
||||||
upath += SRS_HTTP_DEFAULT_PAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
string fullpath = dir + "/";
|
|
||||||
|
|
||||||
// remove the virtual directory.
|
|
||||||
srs_assert(entry);
|
|
||||||
size_t pos = entry->pattern.find("/");
|
|
||||||
if (upath.length() > entry->pattern.length() && pos != string::npos) {
|
|
||||||
fullpath += upath.substr(entry->pattern.length() - pos);
|
|
||||||
} else {
|
|
||||||
fullpath += upath;
|
|
||||||
}
|
|
||||||
|
|
||||||
// stat current dir, if exists, return error.
|
|
||||||
if (!srs_path_exists(fullpath)) {
|
|
||||||
srs_warn("http miss file=%s, pattern=%s, upath=%s",
|
|
||||||
fullpath.c_str(), entry->pattern.c_str(), upath.c_str());
|
|
||||||
return SrsHttpNotFoundHandler().serve_http(w, r);
|
|
||||||
}
|
|
||||||
srs_trace("http match file=%s, pattern=%s, upath=%s",
|
|
||||||
fullpath.c_str(), entry->pattern.c_str(), upath.c_str());
|
|
||||||
|
|
||||||
// handle file according to its extension.
|
|
||||||
// use vod stream for .flv/.fhv
|
|
||||||
if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) {
|
|
||||||
return serve_flv_file(w, r, fullpath);
|
|
||||||
} else if (srs_string_ends_with(fullpath, ".mp4")) {
|
|
||||||
return serve_mp4_file(w, r, fullpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// serve common static file.
|
|
||||||
return serve_file(w, r, fullpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpFileServer::serve_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath)
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
// open the target file.
|
|
||||||
SrsFileReader fs;
|
|
||||||
|
|
||||||
if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) {
|
|
||||||
srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t length = fs.filesize();
|
|
||||||
|
|
||||||
// unset the content length to encode in chunked encoding.
|
|
||||||
w->header()->set_content_length(length);
|
|
||||||
|
|
||||||
static std::map<std::string, std::string> _mime;
|
|
||||||
if (_mime.empty()) {
|
|
||||||
_mime[".ts"] = "video/MP2T";
|
|
||||||
_mime[".flv"] = "video/x-flv";
|
|
||||||
_mime[".m4v"] = "video/x-m4v";
|
|
||||||
_mime[".3gpp"] = "video/3gpp";
|
|
||||||
_mime[".3gp"] = "video/3gpp";
|
|
||||||
_mime[".mp4"] = "video/mp4";
|
|
||||||
_mime[".aac"] = "audio/x-aac";
|
|
||||||
_mime[".mp3"] = "audio/mpeg";
|
|
||||||
_mime[".m4a"] = "audio/x-m4a";
|
|
||||||
_mime[".ogg"] = "audio/ogg";
|
|
||||||
// @see hls-m3u8-draft-pantos-http-live-streaming-12.pdf, page 5.
|
|
||||||
_mime[".m3u8"] = "application/vnd.apple.mpegurl"; // application/x-mpegURL
|
|
||||||
_mime[".rss"] = "application/rss+xml";
|
|
||||||
_mime[".json"] = "application/json";
|
|
||||||
_mime[".swf"] = "application/x-shockwave-flash";
|
|
||||||
_mime[".doc"] = "application/msword";
|
|
||||||
_mime[".zip"] = "application/zip";
|
|
||||||
_mime[".rar"] = "application/x-rar-compressed";
|
|
||||||
_mime[".xml"] = "text/xml";
|
|
||||||
_mime[".html"] = "text/html";
|
|
||||||
_mime[".js"] = "text/javascript";
|
|
||||||
_mime[".css"] = "text/css";
|
|
||||||
_mime[".ico"] = "image/x-icon";
|
|
||||||
_mime[".png"] = "image/png";
|
|
||||||
_mime[".jpeg"] = "image/jpeg";
|
|
||||||
_mime[".jpg"] = "image/jpeg";
|
|
||||||
_mime[".gif"] = "image/gif";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true) {
|
|
||||||
size_t pos;
|
|
||||||
std::string ext = fullpath;
|
|
||||||
if ((pos = ext.rfind(".")) != string::npos) {
|
|
||||||
ext = ext.substr(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_mime.find(ext) == _mime.end()) {
|
|
||||||
w->header()->set_content_type("application/octet-stream");
|
|
||||||
} else {
|
|
||||||
w->header()->set_content_type(_mime[ext]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write body.
|
|
||||||
int64_t left = length;
|
|
||||||
if ((ret = copy(w, &fs, r, (int)left)) != ERROR_SUCCESS) {
|
|
||||||
if (!srs_is_client_gracefully_close(ret)) {
|
|
||||||
srs_error("read file=%s size=%d failed, ret=%d", fullpath.c_str(), left, ret);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return w->final_request();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpFileServer::serve_flv_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath)
|
|
||||||
{
|
|
||||||
std::string start = r->query_get("start");
|
|
||||||
if (start.empty()) {
|
|
||||||
return serve_file(w, r, fullpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
int offset = ::atoi(start.c_str());
|
|
||||||
if (offset <= 0) {
|
|
||||||
return serve_file(w, r, fullpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return serve_flv_stream(w, r, fullpath, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpFileServer::serve_mp4_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath)
|
|
||||||
{
|
|
||||||
// for flash to request mp4 range in query string.
|
|
||||||
// for example, http://digitalprimates.net/dash/DashTest.html?url=http://dashdemo.edgesuite.net/digitalprimates/nexus/oops-20120802-manifest.mpd
|
|
||||||
std::string range = r->query_get("range");
|
|
||||||
// or, use bytes to request range,
|
|
||||||
// for example, http://dashas.castlabs.com/demo/try.html
|
|
||||||
if (range.empty()) {
|
|
||||||
range = r->query_get("bytes");
|
|
||||||
}
|
|
||||||
|
|
||||||
// rollback to serve whole file.
|
|
||||||
size_t pos = string::npos;
|
|
||||||
if (range.empty() || (pos = range.find("-")) == string::npos) {
|
|
||||||
return serve_file(w, r, fullpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the start in query string
|
|
||||||
int start = 0;
|
|
||||||
if (pos > 0) {
|
|
||||||
start = ::atoi(range.substr(0, pos).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse end in query string.
|
|
||||||
int end = -1;
|
|
||||||
if (pos < range.length() - 1) {
|
|
||||||
end = ::atoi(range.substr(pos + 1).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// invalid param, serve as whole mp4 file.
|
|
||||||
if (start < 0 || (end != -1 && start > end)) {
|
|
||||||
return serve_file(w, r, fullpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return serve_mp4_stream(w, r, fullpath, start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpFileServer::serve_flv_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int offset)
|
|
||||||
{
|
|
||||||
return serve_file(w, r, fullpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpFileServer::serve_mp4_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int start, int end)
|
|
||||||
{
|
|
||||||
return serve_file(w, r, fullpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpFileServer::copy(ISrsHttpResponseWriter* w, SrsFileReader* fs, SrsHttpMessage* r, int size)
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
int left = size;
|
|
||||||
char* buf = r->http_ts_send_buffer();
|
|
||||||
|
|
||||||
while (left > 0) {
|
|
||||||
ssize_t nread = -1;
|
|
||||||
int max_read = srs_min(left, SRS_HTTP_TS_SEND_BUFFER_SIZE);
|
|
||||||
if ((ret = fs->read(buf, max_read, &nread)) != ERROR_SUCCESS) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
left -= nread;
|
|
||||||
if ((ret = w->write(buf, (int)nread)) != ERROR_SUCCESS) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpMuxEntry::SrsHttpMuxEntry()
|
|
||||||
{
|
|
||||||
enabled = true;
|
|
||||||
explicit_match = false;
|
|
||||||
handler = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpMuxEntry::~SrsHttpMuxEntry()
|
|
||||||
{
|
|
||||||
srs_freep(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
ISrsHttpMatchHijacker::ISrsHttpMatchHijacker()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ISrsHttpMatchHijacker::~ISrsHttpMatchHijacker()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpServeMux::SrsHttpServeMux()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpServeMux::~SrsHttpServeMux()
|
|
||||||
{
|
|
||||||
std::map<std::string, SrsHttpMuxEntry*>::iterator it;
|
|
||||||
for (it = entries.begin(); it != entries.end(); ++it) {
|
|
||||||
SrsHttpMuxEntry* entry = it->second;
|
|
||||||
srs_freep(entry);
|
|
||||||
}
|
|
||||||
entries.clear();
|
|
||||||
|
|
||||||
vhosts.clear();
|
|
||||||
hijackers.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpServeMux::initialize()
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
// TODO: FIXME: implements it.
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SrsHttpServeMux::hijack(ISrsHttpMatchHijacker* h)
|
|
||||||
{
|
|
||||||
std::vector<ISrsHttpMatchHijacker*>::iterator it = ::find(hijackers.begin(), hijackers.end(), h);
|
|
||||||
if (it != hijackers.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
hijackers.push_back(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SrsHttpServeMux::unhijack(ISrsHttpMatchHijacker* h)
|
|
||||||
{
|
|
||||||
std::vector<ISrsHttpMatchHijacker*>::iterator it = ::find(hijackers.begin(), hijackers.end(), h);
|
|
||||||
if (it == hijackers.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
hijackers.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpServeMux::handle(std::string pattern, ISrsHttpHandler* handler)
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
srs_assert(handler);
|
|
||||||
|
|
||||||
if (pattern.empty()) {
|
|
||||||
ret = ERROR_HTTP_PATTERN_EMPTY;
|
|
||||||
srs_error("http: empty pattern. ret=%d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entries.find(pattern) != entries.end()) {
|
|
||||||
SrsHttpMuxEntry* exists = entries[pattern];
|
|
||||||
if (exists->explicit_match) {
|
|
||||||
ret = ERROR_HTTP_PATTERN_DUPLICATED;
|
|
||||||
srs_error("http: multiple registrations for %s. ret=%d", pattern.c_str(), ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string vhost = pattern;
|
|
||||||
if (pattern.at(0) != '/') {
|
|
||||||
if (pattern.find("/") != string::npos) {
|
|
||||||
vhost = pattern.substr(0, pattern.find("/"));
|
|
||||||
}
|
|
||||||
vhosts[vhost] = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true) {
|
|
||||||
SrsHttpMuxEntry* entry = new SrsHttpMuxEntry();
|
|
||||||
entry->explicit_match = true;
|
|
||||||
entry->handler = handler;
|
|
||||||
entry->pattern = pattern;
|
|
||||||
entry->handler->entry = entry;
|
|
||||||
|
|
||||||
if (entries.find(pattern) != entries.end()) {
|
|
||||||
SrsHttpMuxEntry* exists = entries[pattern];
|
|
||||||
srs_freep(exists);
|
|
||||||
}
|
|
||||||
entries[pattern] = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helpful behavior:
|
|
||||||
// If pattern is /tree/, insert an implicit permanent redirect for /tree.
|
|
||||||
// It can be overridden by an explicit registration.
|
|
||||||
if (pattern != "/" && !pattern.empty() && pattern.at(pattern.length() - 1) == '/') {
|
|
||||||
std::string rpattern = pattern.substr(0, pattern.length() - 1);
|
|
||||||
SrsHttpMuxEntry* entry = NULL;
|
|
||||||
|
|
||||||
// free the exists not explicit entry
|
|
||||||
if (entries.find(rpattern) != entries.end()) {
|
|
||||||
SrsHttpMuxEntry* exists = entries[rpattern];
|
|
||||||
if (!exists->explicit_match) {
|
|
||||||
entry = exists;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create implicit redirect.
|
|
||||||
if (!entry || entry->explicit_match) {
|
|
||||||
srs_freep(entry);
|
|
||||||
|
|
||||||
entry = new SrsHttpMuxEntry();
|
|
||||||
entry->explicit_match = false;
|
|
||||||
entry->handler = new SrsHttpRedirectHandler(pattern, SRS_CONSTS_HTTP_MovedPermanently);
|
|
||||||
entry->pattern = pattern;
|
|
||||||
entry->handler->entry = entry;
|
|
||||||
|
|
||||||
entries[rpattern] = entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpServeMux::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
ISrsHttpHandler* h = NULL;
|
|
||||||
if ((ret = find_handler(r, &h)) != ERROR_SUCCESS) {
|
|
||||||
srs_error("find handler failed. ret=%d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
srs_assert(h);
|
|
||||||
if ((ret = h->serve_http(w, r)) != ERROR_SUCCESS) {
|
|
||||||
if (!srs_is_client_gracefully_close(ret)) {
|
|
||||||
srs_error("handler serve http failed. ret=%d", ret);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpServeMux::find_handler(SrsHttpMessage* r, ISrsHttpHandler** ph)
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
// TODO: FIXME: support the path . and ..
|
|
||||||
if (r->url().find("..") != std::string::npos) {
|
|
||||||
ret = ERROR_HTTP_URL_NOT_CLEAN;
|
|
||||||
srs_error("htt url not canonical, url=%s. ret=%d", r->url().c_str(), ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = match(r, ph)) != ERROR_SUCCESS) {
|
|
||||||
srs_error("http match handler failed. ret=%d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// always hijack.
|
|
||||||
if (!hijackers.empty()) {
|
|
||||||
// notice all hijacker the match failed.
|
|
||||||
std::vector<ISrsHttpMatchHijacker*>::iterator it;
|
|
||||||
for (it = hijackers.begin(); it != hijackers.end(); ++it) {
|
|
||||||
ISrsHttpMatchHijacker* hijacker = *it;
|
|
||||||
if ((ret = hijacker->hijack(r, ph)) != ERROR_SUCCESS) {
|
|
||||||
srs_error("hijacker match failed. ret=%d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*ph == NULL) {
|
|
||||||
// TODO: FIXME: memory leak.
|
|
||||||
*ph = new SrsHttpNotFoundHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsHttpServeMux::match(SrsHttpMessage* r, ISrsHttpHandler** ph)
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
std::string path = r->path();
|
|
||||||
|
|
||||||
// Host-specific pattern takes precedence over generic ones
|
|
||||||
if (!vhosts.empty() && vhosts.find(r->host()) != vhosts.end()) {
|
|
||||||
path = r->host() + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nb_matched = 0;
|
|
||||||
ISrsHttpHandler* h = NULL;
|
|
||||||
|
|
||||||
std::map<std::string, SrsHttpMuxEntry*>::iterator it;
|
|
||||||
for (it = entries.begin(); it != entries.end(); ++it) {
|
|
||||||
std::string pattern = it->first;
|
|
||||||
SrsHttpMuxEntry* entry = it->second;
|
|
||||||
|
|
||||||
if (!entry->enabled) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!path_match(pattern, path)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!h || (int)pattern.length() > nb_matched) {
|
|
||||||
nb_matched = (int)pattern.length();
|
|
||||||
h = entry->handler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*ph = h;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SrsHttpServeMux::path_match(string pattern, string path)
|
|
||||||
{
|
|
||||||
if (pattern.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n = (int)pattern.length();
|
|
||||||
|
|
||||||
// not endswith '/', exactly match.
|
|
||||||
if (pattern.at(n - 1) != '/') {
|
|
||||||
return pattern == path;
|
|
||||||
}
|
|
||||||
|
|
||||||
// endswith '/', match any,
|
|
||||||
// for example, '/api/' match '/api/[N]'
|
|
||||||
if ((int)path.length() >= n) {
|
|
||||||
if (memcmp(pattern.data(), path.data(), n) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsHttpResponseWriter::SrsHttpResponseWriter(SrsStSocket* io)
|
SrsHttpResponseWriter::SrsHttpResponseWriter(SrsStSocket* io)
|
||||||
{
|
{
|
||||||
|
@ -800,7 +91,7 @@ int SrsHttpResponseWriter::write(char* data, int size)
|
||||||
srs_error("http: send header failed. ret=%d", ret);
|
srs_error("http: send header failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore NULL content.
|
// ignore NULL content.
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -854,9 +145,9 @@ int SrsHttpResponseWriter::send_header(char* data, int size)
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
// status_line
|
// status_line
|
||||||
ss << "HTTP/1.1 " << status << " "
|
ss << "HTTP/1.1 " << status << " "
|
||||||
<< srs_generate_http_status_text(status) << SRS_HTTP_CRLF;
|
<< srs_generate_http_status_text(status) << SRS_HTTP_CRLF;
|
||||||
|
|
||||||
// detect content type
|
// detect content type
|
||||||
if (srs_go_http_body_allowd(status)) {
|
if (srs_go_http_body_allowd(status)) {
|
||||||
if (hdr->content_type().empty()) {
|
if (hdr->content_type().empty()) {
|
||||||
|
@ -873,7 +164,7 @@ int SrsHttpResponseWriter::send_header(char* data, int size)
|
||||||
if (content_length == -1) {
|
if (content_length == -1) {
|
||||||
hdr->set("Transfer-Encoding", "chunked");
|
hdr->set("Transfer-Encoding", "chunked");
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep alive to make vlc happy.
|
// keep alive to make vlc happy.
|
||||||
hdr->set("Connection", "Keep-Alive");
|
hdr->set("Connection", "Keep-Alive");
|
||||||
|
|
||||||
|
@ -1036,7 +327,7 @@ int SrsHttpResponseReader::read_chunked(char* data, int nb_data, int* nb_read)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
buffer->read_slice(2);
|
buffer->read_slice(2);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1078,7 +369,7 @@ int SrsHttpResponseReader::read_specified(char* data, int nb_data, int* nb_read)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpMessage::SrsHttpMessage(SrsStSocket* io, SrsConnection* c)
|
SrsHttpMessage::SrsHttpMessage(SrsStSocket* io, SrsConnection* c) : ISrsHttpMessage()
|
||||||
{
|
{
|
||||||
conn = c;
|
conn = c;
|
||||||
chunked = false;
|
chunked = false;
|
||||||
|
@ -1098,11 +389,11 @@ SrsHttpMessage::~SrsHttpMessage()
|
||||||
int SrsHttpMessage::update(string url, http_parser* header, SrsFastBuffer* body, vector<SrsHttpHeaderField>& headers)
|
int SrsHttpMessage::update(string url, http_parser* header, SrsFastBuffer* body, vector<SrsHttpHeaderField>& headers)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
_url = url;
|
_url = url;
|
||||||
_header = *header;
|
_header = *header;
|
||||||
_headers = headers;
|
_headers = headers;
|
||||||
|
|
||||||
// whether chunked.
|
// whether chunked.
|
||||||
std::string transfer_encoding = get_request_header("Transfer-Encoding");
|
std::string transfer_encoding = get_request_header("Transfer-Encoding");
|
||||||
chunked = (transfer_encoding == "chunked");
|
chunked = (transfer_encoding == "chunked");
|
||||||
|
@ -1117,8 +408,8 @@ int SrsHttpMessage::update(string url, http_parser* header, SrsFastBuffer* body,
|
||||||
|
|
||||||
// parse uri from url.
|
// parse uri from url.
|
||||||
std::string host = get_request_header("Host");
|
std::string host = get_request_header("Host");
|
||||||
|
|
||||||
// donot parse the empty host for uri,
|
// donot parse the empty host for uri,
|
||||||
// for example, the response contains no host,
|
// for example, the response contains no host,
|
||||||
// ignore it is ok.
|
// ignore it is ok.
|
||||||
if (host.empty()) {
|
if (host.empty()) {
|
||||||
|
@ -1165,11 +456,6 @@ int SrsHttpMessage::update(string url, http_parser* header, SrsFastBuffer* body,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* SrsHttpMessage::http_ts_send_buffer()
|
|
||||||
{
|
|
||||||
return _http_ts_send_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsConnection* SrsHttpMessage::connection()
|
SrsConnection* SrsHttpMessage::connection()
|
||||||
{
|
{
|
||||||
return conn;
|
return conn;
|
||||||
|
@ -1409,7 +695,7 @@ int SrsHttpParser::initialize(enum http_parser_type type)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsHttpParser::parse_message(SrsStSocket* skt, SrsConnection* conn, SrsHttpMessage** ppmsg)
|
int SrsHttpParser::parse_message(SrsStSocket* skt, SrsConnection* conn, ISrsHttpMessage** ppmsg)
|
||||||
{
|
{
|
||||||
*ppmsg = NULL;
|
*ppmsg = NULL;
|
||||||
|
|
||||||
|
|
|
@ -34,366 +34,22 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <http_parser.h>
|
#include <http_parser.h>
|
||||||
|
|
||||||
#include <srs_app_st.hpp>
|
#include <srs_app_st.hpp>
|
||||||
#include <srs_kernel_consts.hpp>
|
|
||||||
#include <srs_http_stack.hpp>
|
#include <srs_http_stack.hpp>
|
||||||
|
|
||||||
class SrsRequest;
|
class SrsRequest;
|
||||||
class SrsStSocket;
|
class SrsStSocket;
|
||||||
class SrsHttpUri;
|
|
||||||
class SrsHttpMessage;
|
class SrsHttpMessage;
|
||||||
class SrsFileReader;
|
|
||||||
class SrsSimpleBuffer;
|
|
||||||
class SrsHttpMuxEntry;
|
|
||||||
class ISrsHttpResponseWriter;
|
|
||||||
class SrsFastBuffer;
|
class SrsFastBuffer;
|
||||||
|
class SrsHttpUri;
|
||||||
class SrsConnection;
|
class SrsConnection;
|
||||||
|
|
||||||
// http specification
|
|
||||||
// CR = <US-ASCII CR, carriage return (13)>
|
|
||||||
#define SRS_HTTP_CR SRS_CONSTS_CR // 0x0D
|
|
||||||
// LF = <US-ASCII LF, linefeed (10)>
|
|
||||||
#define SRS_HTTP_LF SRS_CONSTS_LF // 0x0A
|
|
||||||
// SP = <US-ASCII SP, space (32)>
|
|
||||||
#define SRS_HTTP_SP ' ' // 0x20
|
|
||||||
// HT = <US-ASCII HT, horizontal-tab (9)>
|
|
||||||
#define SRS_HTTP_HT '\x09' // 0x09
|
|
||||||
|
|
||||||
// HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
|
|
||||||
// protocol elements except the entity-body (see appendix 19.3 for
|
|
||||||
// tolerant applications).
|
|
||||||
#define SRS_HTTP_CRLF "\r\n" // 0x0D0A
|
|
||||||
#define SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
|
|
||||||
|
|
||||||
// @see SrsHttpMessage._http_ts_send_buffer
|
|
||||||
#define SRS_HTTP_TS_SEND_BUFFER_SIZE 4096
|
|
||||||
|
|
||||||
// helper function: response in json format.
|
|
||||||
extern int srs_http_response_json(ISrsHttpResponseWriter* w, std::string data);
|
|
||||||
|
|
||||||
// state of message
|
|
||||||
enum SrsHttpParseState {
|
|
||||||
SrsHttpParseStateInit = 0,
|
|
||||||
SrsHttpParseStateStart,
|
|
||||||
SrsHttpParseStateHeaderComplete,
|
|
||||||
SrsHttpParseStateMessageComplete
|
|
||||||
};
|
|
||||||
|
|
||||||
// A Header represents the key-value pairs in an HTTP header.
|
|
||||||
class SrsHttpHeader
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::map<std::string, std::string> headers;
|
|
||||||
public:
|
|
||||||
SrsHttpHeader();
|
|
||||||
virtual ~SrsHttpHeader();
|
|
||||||
public:
|
|
||||||
// Add adds the key, value pair to the header.
|
|
||||||
// It appends to any existing values associated with key.
|
|
||||||
virtual void set(std::string key, std::string value);
|
|
||||||
// Get gets the first value associated with the given key.
|
|
||||||
// If there are no values associated with the key, Get returns "".
|
|
||||||
// To access multiple values of a key, access the map directly
|
|
||||||
// with CanonicalHeaderKey.
|
|
||||||
virtual std::string get(std::string key);
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* get the content length. -1 if not set.
|
|
||||||
*/
|
|
||||||
virtual int64_t content_length();
|
|
||||||
/**
|
|
||||||
* set the content length by header "Content-Length"
|
|
||||||
*/
|
|
||||||
virtual void set_content_length(int64_t size);
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* get the content type. empty string if not set.
|
|
||||||
*/
|
|
||||||
virtual std::string content_type();
|
|
||||||
/**
|
|
||||||
* set the content type by header "Content-Type"
|
|
||||||
*/
|
|
||||||
virtual void set_content_type(std::string ct);
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* write all headers to string stream.
|
|
||||||
*/
|
|
||||||
virtual void write(std::stringstream& ss);
|
|
||||||
};
|
|
||||||
|
|
||||||
// A ResponseWriter interface is used by an HTTP handler to
|
|
||||||
// construct an HTTP response.
|
|
||||||
// Usage 1, response with specified length content:
|
|
||||||
// ISrsHttpResponseWriter* w; // create or get response.
|
|
||||||
// std::string msg = "Hello, HTTP!";
|
|
||||||
// w->header()->set_content_type("text/plain; charset=utf-8");
|
|
||||||
// w->header()->set_content_length(msg.length());
|
|
||||||
// w->write_header(SRS_CONSTS_HTTP_OK);
|
|
||||||
// w->write((char*)msg.data(), (int)msg.length());
|
|
||||||
// w->final_request(); // optional flush.
|
|
||||||
// Usage 2, response with HTTP code only, zero content length.
|
|
||||||
// ISrsHttpResponseWriter* w; // create or get response.
|
|
||||||
// w->header()->set_content_length(0);
|
|
||||||
// w->write_header(SRS_CONSTS_HTTP_OK);
|
|
||||||
// w->final_request();
|
|
||||||
// Usage 3, response in chunked encoding.
|
|
||||||
// ISrsHttpResponseWriter* w; // create or get response.
|
|
||||||
// std::string msg = "Hello, HTTP!";
|
|
||||||
// w->header()->set_content_type("application/octet-stream");
|
|
||||||
// w->write_header(SRS_CONSTS_HTTP_OK);
|
|
||||||
// w->write((char*)msg.data(), (int)msg.length());
|
|
||||||
// w->write((char*)msg.data(), (int)msg.length());
|
|
||||||
// w->write((char*)msg.data(), (int)msg.length());
|
|
||||||
// w->write((char*)msg.data(), (int)msg.length());
|
|
||||||
// w->final_request(); // required to end the chunked and flush.
|
|
||||||
class ISrsHttpResponseWriter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ISrsHttpResponseWriter();
|
|
||||||
virtual ~ISrsHttpResponseWriter();
|
|
||||||
public:
|
|
||||||
// when chunked mode,
|
|
||||||
// final the request to complete the chunked encoding.
|
|
||||||
// for no-chunked mode,
|
|
||||||
// final to send request, for example, content-length is 0.
|
|
||||||
virtual int final_request() = 0;
|
|
||||||
|
|
||||||
// Header returns the header map that will be sent by WriteHeader.
|
|
||||||
// Changing the header after a call to WriteHeader (or Write) has
|
|
||||||
// no effect.
|
|
||||||
virtual SrsHttpHeader* header() = 0;
|
|
||||||
|
|
||||||
// Write writes the data to the connection as part of an HTTP reply.
|
|
||||||
// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
|
|
||||||
// before writing the data. If the Header does not contain a
|
|
||||||
// Content-Type line, Write adds a Content-Type set to the result of passing
|
|
||||||
// the initial 512 bytes of written data to DetectContentType.
|
|
||||||
// @param data, the data to send. NULL to flush header only.
|
|
||||||
virtual int write(char* data, int size) = 0;
|
|
||||||
|
|
||||||
// WriteHeader sends an HTTP response header with status code.
|
|
||||||
// If WriteHeader is not called explicitly, the first call to Write
|
|
||||||
// will trigger an implicit WriteHeader(http.StatusOK).
|
|
||||||
// Thus explicit calls to WriteHeader are mainly used to
|
|
||||||
// send error codes.
|
|
||||||
// @remark, user must set header then write or write_header.
|
|
||||||
virtual void write_header(int code) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the reader interface for http response.
|
* response writer use st socket
|
||||||
*/
|
*/
|
||||||
class ISrsHttpResponseReader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ISrsHttpResponseReader();
|
|
||||||
virtual ~ISrsHttpResponseReader();
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* whether response read EOF.
|
|
||||||
*/
|
|
||||||
virtual bool eof() = 0;
|
|
||||||
/**
|
|
||||||
* read from the response body.
|
|
||||||
* @param data, the buffer to read data buffer to.
|
|
||||||
* @param nb_data, the max size of data buffer.
|
|
||||||
* @param nb_read, the actual read size of bytes. NULL to ignore.
|
|
||||||
* @remark when eof(), return error.
|
|
||||||
*/
|
|
||||||
virtual int read(char* data, int nb_data, int* nb_read) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Objects implementing the Handler interface can be
|
|
||||||
// registered to serve a particular path or subtree
|
|
||||||
// in the HTTP server.
|
|
||||||
//
|
|
||||||
// ServeHTTP should write reply headers and data to the ResponseWriter
|
|
||||||
// and then return. Returning signals that the request is finished
|
|
||||||
// and that the HTTP server can move on to the next request on
|
|
||||||
// the connection.
|
|
||||||
class ISrsHttpHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SrsHttpMuxEntry* entry;
|
|
||||||
public:
|
|
||||||
ISrsHttpHandler();
|
|
||||||
virtual ~ISrsHttpHandler();
|
|
||||||
public:
|
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Redirect to a fixed URL
|
|
||||||
class SrsHttpRedirectHandler : public ISrsHttpHandler
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::string url;
|
|
||||||
int code;
|
|
||||||
public:
|
|
||||||
SrsHttpRedirectHandler(std::string u, int c);
|
|
||||||
virtual ~SrsHttpRedirectHandler();
|
|
||||||
public:
|
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
|
||||||
};
|
|
||||||
|
|
||||||
// NotFound replies to the request with an HTTP 404 not found error.
|
|
||||||
class SrsHttpNotFoundHandler : public ISrsHttpHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SrsHttpNotFoundHandler();
|
|
||||||
virtual ~SrsHttpNotFoundHandler();
|
|
||||||
public:
|
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
|
||||||
};
|
|
||||||
|
|
||||||
// FileServer returns a handler that serves HTTP requests
|
|
||||||
// with the contents of the file system rooted at root.
|
|
||||||
//
|
|
||||||
// To use the operating system's file system implementation,
|
|
||||||
// use http.Dir:
|
|
||||||
//
|
|
||||||
// http.Handle("/", SrsHttpFileServer("/tmp"))
|
|
||||||
// http.Handle("/", SrsHttpFileServer("static-dir"))
|
|
||||||
class SrsHttpFileServer : public ISrsHttpHandler
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
std::string dir;
|
|
||||||
public:
|
|
||||||
SrsHttpFileServer(std::string root_dir);
|
|
||||||
virtual ~SrsHttpFileServer();
|
|
||||||
public:
|
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* serve the file by specified path
|
|
||||||
*/
|
|
||||||
virtual int serve_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
|
||||||
virtual int serve_flv_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
|
||||||
virtual int serve_mp4_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
|
||||||
protected:
|
|
||||||
/**
|
|
||||||
* when access flv file with x.flv?start=xxx
|
|
||||||
*/
|
|
||||||
virtual int serve_flv_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
|
|
||||||
/**
|
|
||||||
* when access mp4 file with x.mp4?range=start-end
|
|
||||||
* @param start the start offset in bytes.
|
|
||||||
* @param end the end offset in bytes. -1 to end of file.
|
|
||||||
* @remark response data in [start, end].
|
|
||||||
*/
|
|
||||||
virtual int serve_mp4_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int start, int end);
|
|
||||||
protected:
|
|
||||||
/**
|
|
||||||
* copy the fs to response writer in size bytes.
|
|
||||||
*/
|
|
||||||
virtual int copy(ISrsHttpResponseWriter* w, SrsFileReader* fs, SrsHttpMessage* r, int size);
|
|
||||||
};
|
|
||||||
|
|
||||||
// the mux entry for server mux.
|
|
||||||
// the matcher info, for example, the pattern and handler.
|
|
||||||
class SrsHttpMuxEntry
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool explicit_match;
|
|
||||||
ISrsHttpHandler* handler;
|
|
||||||
std::string pattern;
|
|
||||||
bool enabled;
|
|
||||||
public:
|
|
||||||
SrsHttpMuxEntry();
|
|
||||||
virtual ~SrsHttpMuxEntry();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the hijacker for http pattern match.
|
|
||||||
*/
|
|
||||||
class ISrsHttpMatchHijacker
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ISrsHttpMatchHijacker();
|
|
||||||
virtual ~ISrsHttpMatchHijacker();
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* when match the request failed, no handler to process request.
|
|
||||||
* @param request the http request message to match the handler.
|
|
||||||
* @param ph the already matched handler, hijack can rewrite it.
|
|
||||||
*/
|
|
||||||
virtual int hijack(SrsHttpMessage* request, ISrsHttpHandler** ph) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ServeMux is an HTTP request multiplexer.
|
|
||||||
// It matches the URL of each incoming request against a list of registered
|
|
||||||
// patterns and calls the handler for the pattern that
|
|
||||||
// most closely matches the URL.
|
|
||||||
//
|
|
||||||
// Patterns name fixed, rooted paths, like "/favicon.ico",
|
|
||||||
// or rooted subtrees, like "/images/" (note the trailing slash).
|
|
||||||
// Longer patterns take precedence over shorter ones, so that
|
|
||||||
// if there are handlers registered for both "/images/"
|
|
||||||
// and "/images/thumbnails/", the latter handler will be
|
|
||||||
// called for paths beginning "/images/thumbnails/" and the
|
|
||||||
// former will receive requests for any other paths in the
|
|
||||||
// "/images/" subtree.
|
|
||||||
//
|
|
||||||
// Note that since a pattern ending in a slash names a rooted subtree,
|
|
||||||
// the pattern "/" matches all paths not matched by other registered
|
|
||||||
// patterns, not just the URL with Path == "/".
|
|
||||||
//
|
|
||||||
// Patterns may optionally begin with a host name, restricting matches to
|
|
||||||
// URLs on that host only. Host-specific patterns take precedence over
|
|
||||||
// general patterns, so that a handler might register for the two patterns
|
|
||||||
// "/codesearch" and "codesearch.google.com/" without also taking over
|
|
||||||
// requests for "http://www.google.com/".
|
|
||||||
//
|
|
||||||
// ServeMux also takes care of sanitizing the URL request path,
|
|
||||||
// redirecting any request containing . or .. elements to an
|
|
||||||
// equivalent .- and ..-free URL.
|
|
||||||
class SrsHttpServeMux
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
// the pattern handler, to handle the http request.
|
|
||||||
std::map<std::string, SrsHttpMuxEntry*> entries;
|
|
||||||
// the vhost handler.
|
|
||||||
// when find the handler to process the request,
|
|
||||||
// append the matched vhost when pattern not starts with /,
|
|
||||||
// for example, for pattern /live/livestream.flv of vhost ossrs.net,
|
|
||||||
// the path will rewrite to ossrs.net/live/livestream.flv
|
|
||||||
std::map<std::string, ISrsHttpHandler*> vhosts;
|
|
||||||
// all hijackers for http match.
|
|
||||||
// for example, the hstrs(http stream trigger rtmp source)
|
|
||||||
// can hijack and install handler when request incoming and no handler.
|
|
||||||
std::vector<ISrsHttpMatchHijacker*> hijackers;
|
|
||||||
public:
|
|
||||||
SrsHttpServeMux();
|
|
||||||
virtual ~SrsHttpServeMux();
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* initialize the http serve mux.
|
|
||||||
*/
|
|
||||||
virtual int initialize();
|
|
||||||
/**
|
|
||||||
* hijack the http match.
|
|
||||||
*/
|
|
||||||
virtual void hijack(ISrsHttpMatchHijacker* h);
|
|
||||||
virtual void unhijack(ISrsHttpMatchHijacker* h);
|
|
||||||
public:
|
|
||||||
// Handle registers the handler for the given pattern.
|
|
||||||
// If a handler already exists for pattern, Handle panics.
|
|
||||||
virtual int handle(std::string pattern, ISrsHttpHandler* handler);
|
|
||||||
// interface ISrsHttpHandler
|
|
||||||
public:
|
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
|
||||||
private:
|
|
||||||
virtual int find_handler(SrsHttpMessage* r, ISrsHttpHandler** ph);
|
|
||||||
virtual int match(SrsHttpMessage* r, ISrsHttpHandler** ph);
|
|
||||||
virtual bool path_match(std::string pattern, std::string path);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* response writer use st socket
|
|
||||||
*/
|
|
||||||
class SrsHttpResponseWriter : public ISrsHttpResponseWriter
|
class SrsHttpResponseWriter : public ISrsHttpResponseWriter
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -402,7 +58,7 @@ private:
|
||||||
private:
|
private:
|
||||||
// reply header has been (logically) written
|
// reply header has been (logically) written
|
||||||
bool header_wrote;
|
bool header_wrote;
|
||||||
// status code passed to WriteHeader
|
// status code passed to WriteHeader
|
||||||
int status;
|
int status;
|
||||||
private:
|
private:
|
||||||
// explicitly-declared Content-Length; or -1
|
// explicitly-declared Content-Length; or -1
|
||||||
|
@ -427,8 +83,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* response reader use st socket.
|
* response reader use st socket.
|
||||||
*/
|
*/
|
||||||
class SrsHttpResponseReader : virtual public ISrsHttpResponseReader
|
class SrsHttpResponseReader : virtual public ISrsHttpResponseReader
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -447,10 +103,10 @@ public:
|
||||||
virtual ~SrsHttpResponseReader();
|
virtual ~SrsHttpResponseReader();
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* initialize the response reader with buffer.
|
* initialize the response reader with buffer.
|
||||||
*/
|
*/
|
||||||
virtual int initialize(SrsFastBuffer* buffer);
|
virtual int initialize(SrsFastBuffer* buffer);
|
||||||
// interface ISrsHttpResponseReader
|
// interface ISrsHttpResponseReader
|
||||||
public:
|
public:
|
||||||
virtual bool eof();
|
virtual bool eof();
|
||||||
virtual int read(char* data, int nb_data, int* nb_read);
|
virtual int read(char* data, int nb_data, int* nb_read);
|
||||||
|
@ -469,31 +125,31 @@ typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
||||||
// usage. In addition to the notes on the fields below, see the
|
// usage. In addition to the notes on the fields below, see the
|
||||||
// documentation for Request.Write and RoundTripper.
|
// documentation for Request.Write and RoundTripper.
|
||||||
/**
|
/**
|
||||||
* the http message, request or response.
|
* the http message, request or response.
|
||||||
*/
|
*/
|
||||||
class SrsHttpMessage
|
class SrsHttpMessage : public ISrsHttpMessage
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* parsed url.
|
* parsed url.
|
||||||
*/
|
*/
|
||||||
std::string _url;
|
std::string _url;
|
||||||
/**
|
/**
|
||||||
* the extension of file, for example, .flv
|
* the extension of file, for example, .flv
|
||||||
*/
|
*/
|
||||||
std::string _ext;
|
std::string _ext;
|
||||||
/**
|
/**
|
||||||
* parsed http header.
|
* parsed http header.
|
||||||
*/
|
*/
|
||||||
http_parser _header;
|
http_parser _header;
|
||||||
/**
|
/**
|
||||||
* body object, reader object.
|
* body object, reader object.
|
||||||
* @remark, user can get body in string by get_body().
|
* @remark, user can get body in string by get_body().
|
||||||
*/
|
*/
|
||||||
SrsHttpResponseReader* _body;
|
SrsHttpResponseReader* _body;
|
||||||
/**
|
/**
|
||||||
* whether the body is chunked.
|
* whether the body is chunked.
|
||||||
*/
|
*/
|
||||||
bool chunked;
|
bool chunked;
|
||||||
/**
|
/**
|
||||||
* whether the request indicates should keep alive
|
* whether the request indicates should keep alive
|
||||||
|
@ -501,12 +157,12 @@ private:
|
||||||
*/
|
*/
|
||||||
bool keep_alive;
|
bool keep_alive;
|
||||||
/**
|
/**
|
||||||
* uri parser
|
* uri parser
|
||||||
*/
|
*/
|
||||||
SrsHttpUri* _uri;
|
SrsHttpUri* _uri;
|
||||||
/**
|
/**
|
||||||
* use a buffer to read and send ts file.
|
* use a buffer to read and send ts file.
|
||||||
*/
|
*/
|
||||||
// TODO: FIXME: remove it.
|
// TODO: FIXME: remove it.
|
||||||
char* _http_ts_send_buffer;
|
char* _http_ts_send_buffer;
|
||||||
// http headers
|
// http headers
|
||||||
|
@ -520,20 +176,19 @@ public:
|
||||||
virtual ~SrsHttpMessage();
|
virtual ~SrsHttpMessage();
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* set the original messages, then update the message.
|
* set the original messages, then update the message.
|
||||||
*/
|
*/
|
||||||
virtual int update(std::string url, http_parser* header,
|
virtual int update(std::string url, http_parser* header,
|
||||||
SrsFastBuffer* body, std::vector<SrsHttpHeaderField>& headers
|
SrsFastBuffer* body, std::vector<SrsHttpHeaderField>& headers
|
||||||
);
|
);
|
||||||
public:
|
private:
|
||||||
virtual char* http_ts_send_buffer();
|
|
||||||
virtual SrsConnection* connection();
|
virtual SrsConnection* connection();
|
||||||
public:
|
public:
|
||||||
virtual u_int8_t method();
|
virtual u_int8_t method();
|
||||||
virtual u_int16_t status_code();
|
virtual u_int16_t status_code();
|
||||||
/**
|
/**
|
||||||
* method helpers.
|
* method helpers.
|
||||||
*/
|
*/
|
||||||
virtual std::string method_str();
|
virtual std::string method_str();
|
||||||
virtual bool is_http_get();
|
virtual bool is_http_get();
|
||||||
virtual bool is_http_put();
|
virtual bool is_http_put();
|
||||||
|
@ -541,57 +196,57 @@ public:
|
||||||
virtual bool is_http_delete();
|
virtual bool is_http_delete();
|
||||||
virtual bool is_http_options();
|
virtual bool is_http_options();
|
||||||
/**
|
/**
|
||||||
* whether body is chunked encoding, for reader only.
|
* whether body is chunked encoding, for reader only.
|
||||||
*/
|
*/
|
||||||
virtual bool is_chunked();
|
virtual bool is_chunked();
|
||||||
/**
|
/**
|
||||||
* whether should keep the connection alive.
|
* whether should keep the connection alive.
|
||||||
*/
|
*/
|
||||||
virtual bool is_keep_alive();
|
virtual bool is_keep_alive();
|
||||||
/**
|
/**
|
||||||
* the uri contains the host and path.
|
* the uri contains the host and path.
|
||||||
*/
|
*/
|
||||||
virtual std::string uri();
|
virtual std::string uri();
|
||||||
/**
|
/**
|
||||||
* the url maybe the path.
|
* the url maybe the path.
|
||||||
*/
|
*/
|
||||||
virtual std::string url();
|
virtual std::string url();
|
||||||
virtual std::string host();
|
virtual std::string host();
|
||||||
virtual std::string path();
|
virtual std::string path();
|
||||||
virtual std::string ext();
|
virtual std::string ext();
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* read body to string.
|
* read body to string.
|
||||||
* @remark for small http body.
|
* @remark for small http body.
|
||||||
*/
|
*/
|
||||||
virtual int body_read_all(std::string& body);
|
virtual int body_read_all(std::string& body);
|
||||||
/**
|
/**
|
||||||
* get the body reader, to read one by one.
|
* get the body reader, to read one by one.
|
||||||
* @remark when body is very large, or chunked, use this.
|
* @remark when body is very large, or chunked, use this.
|
||||||
*/
|
*/
|
||||||
virtual ISrsHttpResponseReader* body_reader();
|
virtual ISrsHttpResponseReader* body_reader();
|
||||||
/**
|
/**
|
||||||
* the content length, -1 for chunked or not set.
|
* the content length, -1 for chunked or not set.
|
||||||
*/
|
*/
|
||||||
virtual int64_t content_length();
|
virtual int64_t content_length();
|
||||||
/**
|
/**
|
||||||
* get the param in query string,
|
* get the param in query string,
|
||||||
* for instance, query is "start=100&end=200",
|
* for instance, query is "start=100&end=200",
|
||||||
* then query_get("start") is "100", and query_get("end") is "200"
|
* then query_get("start") is "100", and query_get("end") is "200"
|
||||||
*/
|
*/
|
||||||
virtual std::string query_get(std::string key);
|
virtual std::string query_get(std::string key);
|
||||||
/**
|
/**
|
||||||
* get the headers.
|
* get the headers.
|
||||||
*/
|
*/
|
||||||
virtual int request_header_count();
|
virtual int request_header_count();
|
||||||
virtual std::string request_header_key_at(int index);
|
virtual std::string request_header_key_at(int index);
|
||||||
virtual std::string request_header_value_at(int index);
|
virtual std::string request_header_value_at(int index);
|
||||||
virtual std::string get_request_header(std::string name);
|
virtual std::string get_request_header(std::string name);
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* convert the http message to a request.
|
* convert the http message to a request.
|
||||||
* @remark user must free the return request.
|
* @remark user must free the return request.
|
||||||
*/
|
*/
|
||||||
virtual SrsRequest* to_request(std::string vhost);
|
virtual SrsRequest* to_request(std::string vhost);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -631,7 +286,7 @@ public:
|
||||||
* or error and *ppmsg must be NULL.
|
* or error and *ppmsg must be NULL.
|
||||||
* @remark, if success, *ppmsg always NOT-NULL, *ppmsg always is_complete().
|
* @remark, if success, *ppmsg always NOT-NULL, *ppmsg always is_complete().
|
||||||
*/
|
*/
|
||||||
virtual int parse_message(SrsStSocket* skt, SrsConnection* conn, SrsHttpMessage** ppmsg);
|
virtual int parse_message(SrsStSocket* skt, SrsConnection* conn, ISrsHttpMessage** ppmsg);
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* parse the HTTP message to member field: msg.
|
* parse the HTTP message to member field: msg.
|
||||||
|
|
|
@ -48,7 +48,7 @@ SrsGoApiRoot::~SrsGoApiRoot()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiRoot::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsGoApiRoot::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ SrsGoApiApi::~SrsGoApiApi()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiApi::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsGoApiApi::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ SrsGoApiV1::~SrsGoApiV1()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiV1::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsGoApiV1::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ SrsGoApiVersion::~SrsGoApiVersion()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiVersion::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsGoApiVersion::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ SrsGoApiSummaries::~SrsGoApiSummaries()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiSummaries::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsGoApiSummaries::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
srs_api_dump_summaries(ss);
|
srs_api_dump_summaries(ss);
|
||||||
|
@ -163,7 +163,7 @@ SrsGoApiRusages::~SrsGoApiRusages()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiRusages::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* req)
|
int SrsGoApiRusages::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* req)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ SrsGoApiSelfProcStats::~SrsGoApiSelfProcStats()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiSelfProcStats::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsGoApiSelfProcStats::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
@ -274,7 +274,7 @@ SrsGoApiSystemProcStats::~SrsGoApiSystemProcStats()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiSystemProcStats::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsGoApiSystemProcStats::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
@ -309,7 +309,7 @@ SrsGoApiMemInfos::~SrsGoApiMemInfos()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiMemInfos::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsGoApiMemInfos::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
@ -345,7 +345,7 @@ SrsGoApiAuthors::~SrsGoApiAuthors()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
@ -370,9 +370,9 @@ SrsGoApiRequests::~SrsGoApiRequests()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiRequests::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsGoApiRequests::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
SrsHttpMessage* req = r;
|
ISrsHttpMessage* req = r;
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
@ -431,7 +431,7 @@ SrsGoApiVhosts::~SrsGoApiVhosts()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
std::stringstream data;
|
std::stringstream data;
|
||||||
SrsStatistic* stat = SrsStatistic::instance();
|
SrsStatistic* stat = SrsStatistic::instance();
|
||||||
|
@ -456,7 +456,7 @@ SrsGoApiStreams::~SrsGoApiStreams()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
std::stringstream data;
|
std::stringstream data;
|
||||||
SrsStatistic* stat = SrsStatistic::instance();
|
SrsStatistic* stat = SrsStatistic::instance();
|
||||||
|
@ -529,7 +529,7 @@ int SrsHttpApi::do_cycle()
|
||||||
|
|
||||||
// process http messages.
|
// process http messages.
|
||||||
for (;;) {
|
for (;;) {
|
||||||
SrsHttpMessage* req = NULL;
|
ISrsHttpMessage* req = NULL;
|
||||||
|
|
||||||
// get a http message
|
// get a http message
|
||||||
if ((ret = parser->parse_message(&skt, this, &req)) != ERROR_SUCCESS) {
|
if ((ret = parser->parse_message(&skt, this, &req)) != ERROR_SUCCESS) {
|
||||||
|
@ -540,7 +540,7 @@ int SrsHttpApi::do_cycle()
|
||||||
srs_assert(req);
|
srs_assert(req);
|
||||||
|
|
||||||
// always free it in this scope.
|
// always free it in this scope.
|
||||||
SrsAutoFree(SrsHttpMessage, req);
|
SrsAutoFree(ISrsHttpMessage, req);
|
||||||
|
|
||||||
// TODO: FIXME: use the post body.
|
// TODO: FIXME: use the post body.
|
||||||
std::string res;
|
std::string res;
|
||||||
|
@ -566,7 +566,7 @@ int SrsHttpApi::do_cycle()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsHttpApi::process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsHttpApi::process_request(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#ifdef SRS_AUTO_HTTP_API
|
#ifdef SRS_AUTO_HTTP_API
|
||||||
|
|
||||||
class SrsStSocket;
|
class SrsStSocket;
|
||||||
class SrsHttpMessage;
|
class ISrsHttpMessage;
|
||||||
class SrsHttpParser;
|
class SrsHttpParser;
|
||||||
class SrsHttpHandler;
|
class SrsHttpHandler;
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ public:
|
||||||
SrsGoApiRoot();
|
SrsGoApiRoot();
|
||||||
virtual ~SrsGoApiRoot();
|
virtual ~SrsGoApiRoot();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGoApiApi : public ISrsHttpHandler
|
class SrsGoApiApi : public ISrsHttpHandler
|
||||||
|
@ -57,7 +57,7 @@ public:
|
||||||
SrsGoApiApi();
|
SrsGoApiApi();
|
||||||
virtual ~SrsGoApiApi();
|
virtual ~SrsGoApiApi();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGoApiV1 : public ISrsHttpHandler
|
class SrsGoApiV1 : public ISrsHttpHandler
|
||||||
|
@ -66,7 +66,7 @@ public:
|
||||||
SrsGoApiV1();
|
SrsGoApiV1();
|
||||||
virtual ~SrsGoApiV1();
|
virtual ~SrsGoApiV1();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGoApiVersion : public ISrsHttpHandler
|
class SrsGoApiVersion : public ISrsHttpHandler
|
||||||
|
@ -75,7 +75,7 @@ public:
|
||||||
SrsGoApiVersion();
|
SrsGoApiVersion();
|
||||||
virtual ~SrsGoApiVersion();
|
virtual ~SrsGoApiVersion();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGoApiSummaries : public ISrsHttpHandler
|
class SrsGoApiSummaries : public ISrsHttpHandler
|
||||||
|
@ -84,7 +84,7 @@ public:
|
||||||
SrsGoApiSummaries();
|
SrsGoApiSummaries();
|
||||||
virtual ~SrsGoApiSummaries();
|
virtual ~SrsGoApiSummaries();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGoApiRusages : public ISrsHttpHandler
|
class SrsGoApiRusages : public ISrsHttpHandler
|
||||||
|
@ -93,7 +93,7 @@ public:
|
||||||
SrsGoApiRusages();
|
SrsGoApiRusages();
|
||||||
virtual ~SrsGoApiRusages();
|
virtual ~SrsGoApiRusages();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGoApiSelfProcStats : public ISrsHttpHandler
|
class SrsGoApiSelfProcStats : public ISrsHttpHandler
|
||||||
|
@ -102,7 +102,7 @@ public:
|
||||||
SrsGoApiSelfProcStats();
|
SrsGoApiSelfProcStats();
|
||||||
virtual ~SrsGoApiSelfProcStats();
|
virtual ~SrsGoApiSelfProcStats();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGoApiSystemProcStats : public ISrsHttpHandler
|
class SrsGoApiSystemProcStats : public ISrsHttpHandler
|
||||||
|
@ -111,7 +111,7 @@ public:
|
||||||
SrsGoApiSystemProcStats();
|
SrsGoApiSystemProcStats();
|
||||||
virtual ~SrsGoApiSystemProcStats();
|
virtual ~SrsGoApiSystemProcStats();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGoApiMemInfos : public ISrsHttpHandler
|
class SrsGoApiMemInfos : public ISrsHttpHandler
|
||||||
|
@ -120,7 +120,7 @@ public:
|
||||||
SrsGoApiMemInfos();
|
SrsGoApiMemInfos();
|
||||||
virtual ~SrsGoApiMemInfos();
|
virtual ~SrsGoApiMemInfos();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGoApiAuthors : public ISrsHttpHandler
|
class SrsGoApiAuthors : public ISrsHttpHandler
|
||||||
|
@ -129,7 +129,7 @@ public:
|
||||||
SrsGoApiAuthors();
|
SrsGoApiAuthors();
|
||||||
virtual ~SrsGoApiAuthors();
|
virtual ~SrsGoApiAuthors();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGoApiRequests : public ISrsHttpHandler
|
class SrsGoApiRequests : public ISrsHttpHandler
|
||||||
|
@ -138,7 +138,7 @@ public:
|
||||||
SrsGoApiRequests();
|
SrsGoApiRequests();
|
||||||
virtual ~SrsGoApiRequests();
|
virtual ~SrsGoApiRequests();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGoApiVhosts : public ISrsHttpHandler
|
class SrsGoApiVhosts : public ISrsHttpHandler
|
||||||
|
@ -147,7 +147,7 @@ public:
|
||||||
SrsGoApiVhosts();
|
SrsGoApiVhosts();
|
||||||
virtual ~SrsGoApiVhosts();
|
virtual ~SrsGoApiVhosts();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGoApiStreams : public ISrsHttpHandler
|
class SrsGoApiStreams : public ISrsHttpHandler
|
||||||
|
@ -156,7 +156,7 @@ public:
|
||||||
SrsGoApiStreams();
|
SrsGoApiStreams();
|
||||||
virtual ~SrsGoApiStreams();
|
virtual ~SrsGoApiStreams();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsHttpApi : public SrsConnection
|
class SrsHttpApi : public SrsConnection
|
||||||
|
@ -177,7 +177,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
virtual int do_cycle();
|
virtual int do_cycle();
|
||||||
private:
|
private:
|
||||||
virtual int process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int process_request(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -71,7 +71,7 @@ int SrsHttpClient::initialize(string h, int p, int64_t t_us)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsHttpClient::post(string path, string req, SrsHttpMessage** ppmsg)
|
int SrsHttpClient::post(string path, string req, ISrsHttpMessage** ppmsg)
|
||||||
{
|
{
|
||||||
*ppmsg = NULL;
|
*ppmsg = NULL;
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ int SrsHttpClient::post(string path, string req, SrsHttpMessage** ppmsg)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpMessage* msg = NULL;
|
ISrsHttpMessage* msg = NULL;
|
||||||
if ((ret = parser->parse_message(skt, NULL, &msg)) != ERROR_SUCCESS) {
|
if ((ret = parser->parse_message(skt, NULL, &msg)) != ERROR_SUCCESS) {
|
||||||
srs_error("parse http post response failed. ret=%d", ret);
|
srs_error("parse http post response failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -117,7 +117,7 @@ int SrsHttpClient::post(string path, string req, SrsHttpMessage** ppmsg)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsHttpClient::get(string path, std::string req, SrsHttpMessage** ppmsg)
|
int SrsHttpClient::get(string path, std::string req, ISrsHttpMessage** ppmsg)
|
||||||
{
|
{
|
||||||
*ppmsg = NULL;
|
*ppmsg = NULL;
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ int SrsHttpClient::get(string path, std::string req, SrsHttpMessage** ppmsg)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpMessage* msg = NULL;
|
ISrsHttpMessage* msg = NULL;
|
||||||
if ((ret = parser->parse_message(skt, NULL, &msg)) != ERROR_SUCCESS) {
|
if ((ret = parser->parse_message(skt, NULL, &msg)) != ERROR_SUCCESS) {
|
||||||
srs_error("parse http post response failed. ret=%d", ret);
|
srs_error("parse http post response failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -37,7 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
class SrsHttpUri;
|
class SrsHttpUri;
|
||||||
class SrsHttpParser;
|
class SrsHttpParser;
|
||||||
class SrsHttpMessage;
|
class ISrsHttpMessage;
|
||||||
class SrsStSocket;
|
class SrsStSocket;
|
||||||
|
|
||||||
// the default timeout for http client.
|
// the default timeout for http client.
|
||||||
|
@ -73,14 +73,14 @@ public:
|
||||||
* @param req the data post to uri. empty string to ignore.
|
* @param req the data post to uri. empty string to ignore.
|
||||||
* @param ppmsg output the http message to read the response.
|
* @param ppmsg output the http message to read the response.
|
||||||
*/
|
*/
|
||||||
virtual int post(std::string path, std::string req, SrsHttpMessage** ppmsg);
|
virtual int post(std::string path, std::string req, ISrsHttpMessage** ppmsg);
|
||||||
/**
|
/**
|
||||||
* to get data from the uri.
|
* to get data from the uri.
|
||||||
* @param the path to request on.
|
* @param the path to request on.
|
||||||
* @param req the data post to uri. empty string to ignore.
|
* @param req the data post to uri. empty string to ignore.
|
||||||
* @param ppmsg output the http message to read the response.
|
* @param ppmsg output the http message to read the response.
|
||||||
*/
|
*/
|
||||||
virtual int get(std::string path, std::string req, SrsHttpMessage** ppmsg);
|
virtual int get(std::string path, std::string req, ISrsHttpMessage** ppmsg);
|
||||||
private:
|
private:
|
||||||
virtual void disconnect();
|
virtual void disconnect();
|
||||||
virtual int connect();
|
virtual int connect();
|
||||||
|
|
|
@ -60,7 +60,7 @@ SrsVodStream::~SrsVodStream()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsVodStream::serve_flv_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int offset)
|
int SrsVodStream::serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath, int offset)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ int SrsVodStream::serve_flv_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsVodStream::serve_mp4_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int start, int end)
|
int SrsVodStream::serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath, int start, int end)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
@ -567,7 +567,7 @@ SrsLiveStream::~SrsLiveStream()
|
||||||
srs_freep(req);
|
srs_freep(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsLiveStream::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsLiveStream::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
@ -743,7 +743,7 @@ void SrsHlsM3u8Stream::set_m3u8(std::string v)
|
||||||
m3u8 = v;
|
m3u8 = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsHlsM3u8Stream::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsHlsM3u8Stream::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
@ -775,7 +775,7 @@ void SrsHlsTsStream::set_ts(std::string v)
|
||||||
ts = v;
|
ts = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsHlsTsStream::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsHlsTsStream::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
@ -1110,7 +1110,7 @@ int SrsHttpServer::on_reload_vhost_hls(string vhost)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsHttpServer::hijack(SrsHttpMessage* request, ISrsHttpHandler** ph)
|
int SrsHttpServer::hijack(ISrsHttpMessage* request, ISrsHttpHandler** ph)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
@ -1169,8 +1169,12 @@ int SrsHttpServer::hijack(SrsHttpMessage* request, ISrsHttpHandler** ph)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convert to concreate class.
|
||||||
|
SrsHttpMessage* hreq = dynamic_cast<SrsHttpMessage*>(request);
|
||||||
|
srs_assert(hreq);
|
||||||
|
|
||||||
// hijack for entry.
|
// hijack for entry.
|
||||||
SrsRequest* r = request->to_request(vhost->arg0());
|
SrsRequest* r = hreq->to_request(vhost->arg0());
|
||||||
SrsAutoFree(SrsRequest, r);
|
SrsAutoFree(SrsRequest, r);
|
||||||
SrsSource* s = SrsSource::fetch(r);
|
SrsSource* s = SrsSource::fetch(r);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
|
@ -1389,7 +1393,7 @@ int SrsHttpConn::do_cycle()
|
||||||
|
|
||||||
// process http messages.
|
// process http messages.
|
||||||
for (;;) {
|
for (;;) {
|
||||||
SrsHttpMessage* req = NULL;
|
ISrsHttpMessage* req = NULL;
|
||||||
|
|
||||||
// get a http message
|
// get a http message
|
||||||
if ((ret = parser->parse_message(&skt, this, &req)) != ERROR_SUCCESS) {
|
if ((ret = parser->parse_message(&skt, this, &req)) != ERROR_SUCCESS) {
|
||||||
|
@ -1400,7 +1404,7 @@ int SrsHttpConn::do_cycle()
|
||||||
srs_assert(req);
|
srs_assert(req);
|
||||||
|
|
||||||
// always free it in this scope.
|
// always free it in this scope.
|
||||||
SrsAutoFree(SrsHttpMessage, req);
|
SrsAutoFree(ISrsHttpMessage, req);
|
||||||
|
|
||||||
// may should discard the body.
|
// may should discard the body.
|
||||||
if ((ret = on_got_http_message(req)) != ERROR_SUCCESS) {
|
if ((ret = on_got_http_message(req)) != ERROR_SUCCESS) {
|
||||||
|
@ -1423,7 +1427,7 @@ int SrsHttpConn::do_cycle()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsHttpConn::process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
int SrsHttpConn::process_request(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
@ -1450,7 +1454,7 @@ SrsStaticHttpConn::~SrsStaticHttpConn()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsStaticHttpConn::on_got_http_message(SrsHttpMessage* msg)
|
int SrsStaticHttpConn::on_got_http_message(ISrsHttpMessage* msg)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ class SrsAacEncoder;
|
||||||
class SrsMp3Encoder;
|
class SrsMp3Encoder;
|
||||||
class SrsFlvEncoder;
|
class SrsFlvEncoder;
|
||||||
class SrsHttpParser;
|
class SrsHttpParser;
|
||||||
class SrsHttpMessage;
|
class ISrsHttpMessage;
|
||||||
class SrsHttpHandler;
|
class SrsHttpHandler;
|
||||||
class SrsMessageQueue;
|
class SrsMessageQueue;
|
||||||
class SrsSharedPtrMessage;
|
class SrsSharedPtrMessage;
|
||||||
|
@ -66,8 +66,8 @@ public:
|
||||||
SrsVodStream(std::string root_dir);
|
SrsVodStream(std::string root_dir);
|
||||||
virtual ~SrsVodStream();
|
virtual ~SrsVodStream();
|
||||||
protected:
|
protected:
|
||||||
virtual int serve_flv_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
|
virtual int serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath, int offset);
|
||||||
virtual int serve_mp4_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int start, int end);
|
virtual int serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath, int start, int end);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -243,7 +243,7 @@ public:
|
||||||
SrsLiveStream(SrsSource* s, SrsRequest* r, SrsStreamCache* c);
|
SrsLiveStream(SrsSource* s, SrsRequest* r, SrsStreamCache* c);
|
||||||
virtual ~SrsLiveStream();
|
virtual ~SrsLiveStream();
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
private:
|
private:
|
||||||
virtual int streaming_send_messages(ISrsStreamEncoder* enc, SrsSharedPtrMessage** msgs, int nb_msgs);
|
virtual int streaming_send_messages(ISrsStreamEncoder* enc, SrsSharedPtrMessage** msgs, int nb_msgs);
|
||||||
};
|
};
|
||||||
|
@ -289,7 +289,7 @@ public:
|
||||||
public:
|
public:
|
||||||
virtual void set_m3u8(std::string v);
|
virtual void set_m3u8(std::string v);
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -305,7 +305,7 @@ public:
|
||||||
public:
|
public:
|
||||||
virtual void set_ts(std::string v);
|
virtual void set_ts(std::string v);
|
||||||
public:
|
public:
|
||||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -365,7 +365,7 @@ public:
|
||||||
virtual int on_reload_vhost_hls(std::string vhost);
|
virtual int on_reload_vhost_hls(std::string vhost);
|
||||||
// interface ISrsHttpMatchHijacker
|
// interface ISrsHttpMatchHijacker
|
||||||
public:
|
public:
|
||||||
virtual int hijack(SrsHttpMessage* request, ISrsHttpHandler** ph);
|
virtual int hijack(ISrsHttpMessage* request, ISrsHttpHandler** ph);
|
||||||
private:
|
private:
|
||||||
virtual int initialize_static_file();
|
virtual int initialize_static_file();
|
||||||
virtual int initialize_flv_streaming();
|
virtual int initialize_flv_streaming();
|
||||||
|
@ -392,9 +392,9 @@ protected:
|
||||||
// when got http message,
|
// when got http message,
|
||||||
// for the static service or api, discard any body.
|
// for the static service or api, discard any body.
|
||||||
// for the stream caster, for instance, http flv streaming, may discard the flv header or not.
|
// for the stream caster, for instance, http flv streaming, may discard the flv header or not.
|
||||||
virtual int on_got_http_message(SrsHttpMessage* msg) = 0;
|
virtual int on_got_http_message(ISrsHttpMessage* msg) = 0;
|
||||||
private:
|
private:
|
||||||
virtual int process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
virtual int process_request(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsStaticHttpConn : public SrsHttpConn
|
class SrsStaticHttpConn : public SrsHttpConn
|
||||||
|
@ -403,7 +403,7 @@ public:
|
||||||
SrsStaticHttpConn(IConnectionManager* cm, st_netfd_t fd, SrsHttpServeMux* m);
|
SrsStaticHttpConn(IConnectionManager* cm, st_netfd_t fd, SrsHttpServeMux* m);
|
||||||
virtual ~SrsStaticHttpConn();
|
virtual ~SrsStaticHttpConn();
|
||||||
public:
|
public:
|
||||||
virtual int on_got_http_message(SrsHttpMessage* msg);
|
virtual int on_got_http_message(ISrsHttpMessage* msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -371,11 +371,11 @@ int SrsHttpHooks::on_hls_notify(std::string url, SrsRequest* req, std::string ts
|
||||||
}
|
}
|
||||||
srs_warn("GET %s", path.c_str());
|
srs_warn("GET %s", path.c_str());
|
||||||
|
|
||||||
SrsHttpMessage* msg = NULL;
|
ISrsHttpMessage* msg = NULL;
|
||||||
if ((ret = http.get(path.c_str(), "", &msg)) != ERROR_SUCCESS) {
|
if ((ret = http.get(path.c_str(), "", &msg)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
SrsAutoFree(SrsHttpMessage, msg);
|
SrsAutoFree(ISrsHttpMessage, msg);
|
||||||
|
|
||||||
int nb_buf = srs_min(nb_notify, SRS_HTTP_READ_BUFFER);
|
int nb_buf = srs_min(nb_notify, SRS_HTTP_READ_BUFFER);
|
||||||
char* buf = new char[nb_buf];
|
char* buf = new char[nb_buf];
|
||||||
|
@ -416,11 +416,11 @@ int SrsHttpHooks::do_post(std::string url, std::string req, int& code, string& r
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpMessage* msg = NULL;
|
ISrsHttpMessage* msg = NULL;
|
||||||
if ((ret = http.post(uri.get_path(), req, &msg)) != ERROR_SUCCESS) {
|
if ((ret = http.post(uri.get_path(), req, &msg)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
SrsAutoFree(SrsHttpMessage, msg);
|
SrsAutoFree(ISrsHttpMessage, msg);
|
||||||
|
|
||||||
code = msg->status_code();
|
code = msg->status_code();
|
||||||
if ((ret = msg->body_read_all(res)) != ERROR_SUCCESS) {
|
if ((ret = msg->body_read_all(res)) != ERROR_SUCCESS) {
|
||||||
|
|
|
@ -383,14 +383,14 @@ int SrsIngestSrsInput::parseM3u8(SrsHttpUri* url, double& td, double& duration)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpMessage* msg = NULL;
|
ISrsHttpMessage* msg = NULL;
|
||||||
if ((ret = client.get(url->get_path(), "", &msg)) != ERROR_SUCCESS) {
|
if ((ret = client.get(url->get_path(), "", &msg)) != ERROR_SUCCESS) {
|
||||||
srs_error("HTTP GET %s failed. ret=%d", url->get_url(), ret);
|
srs_error("HTTP GET %s failed. ret=%d", url->get_url(), ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_assert(msg);
|
srs_assert(msg);
|
||||||
SrsAutoFree(SrsHttpMessage, msg);
|
SrsAutoFree(ISrsHttpMessage, msg);
|
||||||
|
|
||||||
std::string body;
|
std::string body;
|
||||||
if ((ret = msg->body_read_all(body)) != ERROR_SUCCESS) {
|
if ((ret = msg->body_read_all(body)) != ERROR_SUCCESS) {
|
||||||
|
@ -605,14 +605,14 @@ int SrsIngestSrsInput::SrsTsPiece::fetch(string m3u8)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpMessage* msg = NULL;
|
ISrsHttpMessage* msg = NULL;
|
||||||
if ((ret = client.get(uri.get_path(), "", &msg)) != ERROR_SUCCESS) {
|
if ((ret = client.get(uri.get_path(), "", &msg)) != ERROR_SUCCESS) {
|
||||||
srs_error("HTTP GET %s failed. ret=%d", uri.get_url(), ret);
|
srs_error("HTTP GET %s failed. ret=%d", uri.get_url(), ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_assert(msg);
|
srs_assert(msg);
|
||||||
SrsAutoFree(SrsHttpMessage, msg);
|
SrsAutoFree(ISrsHttpMessage, msg);
|
||||||
|
|
||||||
if ((ret = msg->body_read_all(body)) != ERROR_SUCCESS) {
|
if ((ret = msg->body_read_all(body)) != ERROR_SUCCESS) {
|
||||||
srs_error("read ts failed. ret=%d", ret);
|
srs_error("read ts failed. ret=%d", ret);
|
||||||
|
|
|
@ -22,3 +22,717 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <srs_http_stack.hpp>
|
#include <srs_http_stack.hpp>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#include <srs_kernel_error.hpp>
|
||||||
|
#include <srs_kernel_log.hpp>
|
||||||
|
#include <srs_kernel_utility.hpp>
|
||||||
|
#include <srs_kernel_file.hpp>
|
||||||
|
|
||||||
|
#define SRS_HTTP_DEFAULT_PAGE "index.html"
|
||||||
|
|
||||||
|
// get the status text of code.
|
||||||
|
string srs_generate_http_status_text(int status)
|
||||||
|
{
|
||||||
|
static std::map<int, std::string> _status_map;
|
||||||
|
if (_status_map.empty()) {
|
||||||
|
_status_map[SRS_CONSTS_HTTP_Continue ] = SRS_CONSTS_HTTP_Continue_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_SwitchingProtocols ] = SRS_CONSTS_HTTP_SwitchingProtocols_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_OK ] = SRS_CONSTS_HTTP_OK_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_Created ] = SRS_CONSTS_HTTP_Created_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_Accepted ] = SRS_CONSTS_HTTP_Accepted_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_NonAuthoritativeInformation ] = SRS_CONSTS_HTTP_NonAuthoritativeInformation_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_NoContent ] = SRS_CONSTS_HTTP_NoContent_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_ResetContent ] = SRS_CONSTS_HTTP_ResetContent_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_PartialContent ] = SRS_CONSTS_HTTP_PartialContent_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_MultipleChoices ] = SRS_CONSTS_HTTP_MultipleChoices_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_MovedPermanently ] = SRS_CONSTS_HTTP_MovedPermanently_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_Found ] = SRS_CONSTS_HTTP_Found_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_SeeOther ] = SRS_CONSTS_HTTP_SeeOther_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_NotModified ] = SRS_CONSTS_HTTP_NotModified_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_UseProxy ] = SRS_CONSTS_HTTP_UseProxy_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_TemporaryRedirect ] = SRS_CONSTS_HTTP_TemporaryRedirect_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_BadRequest ] = SRS_CONSTS_HTTP_BadRequest_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_Unauthorized ] = SRS_CONSTS_HTTP_Unauthorized_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_PaymentRequired ] = SRS_CONSTS_HTTP_PaymentRequired_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_Forbidden ] = SRS_CONSTS_HTTP_Forbidden_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_NotFound ] = SRS_CONSTS_HTTP_NotFound_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_MethodNotAllowed ] = SRS_CONSTS_HTTP_MethodNotAllowed_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_NotAcceptable ] = SRS_CONSTS_HTTP_NotAcceptable_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_ProxyAuthenticationRequired ] = SRS_CONSTS_HTTP_ProxyAuthenticationRequired_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_RequestTimeout ] = SRS_CONSTS_HTTP_RequestTimeout_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_Conflict ] = SRS_CONSTS_HTTP_Conflict_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_Gone ] = SRS_CONSTS_HTTP_Gone_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_LengthRequired ] = SRS_CONSTS_HTTP_LengthRequired_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_PreconditionFailed ] = SRS_CONSTS_HTTP_PreconditionFailed_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_RequestEntityTooLarge ] = SRS_CONSTS_HTTP_RequestEntityTooLarge_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_RequestURITooLarge ] = SRS_CONSTS_HTTP_RequestURITooLarge_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_UnsupportedMediaType ] = SRS_CONSTS_HTTP_UnsupportedMediaType_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_RequestedRangeNotSatisfiable ] = SRS_CONSTS_HTTP_RequestedRangeNotSatisfiable_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_ExpectationFailed ] = SRS_CONSTS_HTTP_ExpectationFailed_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_InternalServerError ] = SRS_CONSTS_HTTP_InternalServerError_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_NotImplemented ] = SRS_CONSTS_HTTP_NotImplemented_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_BadGateway ] = SRS_CONSTS_HTTP_BadGateway_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_ServiceUnavailable ] = SRS_CONSTS_HTTP_ServiceUnavailable_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_GatewayTimeout ] = SRS_CONSTS_HTTP_GatewayTimeout_str ;
|
||||||
|
_status_map[SRS_CONSTS_HTTP_HTTPVersionNotSupported ] = SRS_CONSTS_HTTP_HTTPVersionNotSupported_str ;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string status_text;
|
||||||
|
if (_status_map.find(status) == _status_map.end()) {
|
||||||
|
status_text = "Status Unknown";
|
||||||
|
} else {
|
||||||
|
status_text = _status_map[status];
|
||||||
|
}
|
||||||
|
|
||||||
|
return status_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bodyAllowedForStatus reports whether a given response status code
|
||||||
|
// permits a body. See RFC2616, section 4.4.
|
||||||
|
bool srs_go_http_body_allowd(int status)
|
||||||
|
{
|
||||||
|
if (status >= 100 && status <= 199) {
|
||||||
|
return false;
|
||||||
|
} else if (status == 204 || status == 304) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetectContentType implements the algorithm described
|
||||||
|
// at http://mimesniff.spec.whatwg.org/ to determine the
|
||||||
|
// Content-Type of the given data. It considers at most the
|
||||||
|
// first 512 bytes of data. DetectContentType always returns
|
||||||
|
// a valid MIME type: if it cannot determine a more specific one, it
|
||||||
|
// returns "application/octet-stream".
|
||||||
|
string srs_go_http_detect(char* data, int size)
|
||||||
|
{
|
||||||
|
// detect only when data specified.
|
||||||
|
if (data) {
|
||||||
|
}
|
||||||
|
return "application/octet-stream"; // fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error replies to the request with the specified error message and HTTP code.
|
||||||
|
// The error message should be plain text.
|
||||||
|
int srs_go_http_error(ISrsHttpResponseWriter* w, int code, string error)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
w->header()->set_content_type("text/plain; charset=utf-8");
|
||||||
|
w->header()->set_content_length(error.length());
|
||||||
|
w->write_header(code);
|
||||||
|
w->write((char*)error.data(), (int)error.length());
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpHeader::SrsHttpHeader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpHeader::~SrsHttpHeader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsHttpHeader::set(string key, string value)
|
||||||
|
{
|
||||||
|
headers[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
string SrsHttpHeader::get(string key)
|
||||||
|
{
|
||||||
|
std::string v;
|
||||||
|
|
||||||
|
if (headers.find(key) != headers.end()) {
|
||||||
|
v = headers[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t SrsHttpHeader::content_length()
|
||||||
|
{
|
||||||
|
std::string cl = get("Content-Length");
|
||||||
|
|
||||||
|
if (cl.empty()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int64_t)::atof(cl.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsHttpHeader::set_content_length(int64_t size)
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
snprintf(buf, sizeof(buf), "%"PRId64, size);
|
||||||
|
set("Content-Length", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
string SrsHttpHeader::content_type()
|
||||||
|
{
|
||||||
|
return get("Content-Type");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsHttpHeader::set_content_type(string ct)
|
||||||
|
{
|
||||||
|
set("Content-Type", ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsHttpHeader::write(stringstream& ss)
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string>::iterator it;
|
||||||
|
for (it = headers.begin(); it != headers.end(); ++it) {
|
||||||
|
ss << it->first << ": " << it->second << SRS_HTTP_CRLF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsHttpResponseWriter::ISrsHttpResponseWriter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsHttpResponseWriter::~ISrsHttpResponseWriter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsHttpResponseReader::ISrsHttpResponseReader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsHttpResponseReader::~ISrsHttpResponseReader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsHttpHandler::ISrsHttpHandler()
|
||||||
|
{
|
||||||
|
entry = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsHttpHandler::~ISrsHttpHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpRedirectHandler::SrsHttpRedirectHandler(string u, int c)
|
||||||
|
{
|
||||||
|
url = u;
|
||||||
|
code = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpRedirectHandler::~SrsHttpRedirectHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpRedirectHandler::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
// TODO: FIXME: implements it.
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpNotFoundHandler::SrsHttpNotFoundHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpNotFoundHandler::~SrsHttpNotFoundHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpNotFoundHandler::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
|
{
|
||||||
|
return srs_go_http_error(w, SRS_CONSTS_HTTP_NotFound, SRS_CONSTS_HTTP_NotFound_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpFileServer::SrsHttpFileServer(string root_dir)
|
||||||
|
{
|
||||||
|
dir = root_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpFileServer::~SrsHttpFileServer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpFileServer::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
|
{
|
||||||
|
string upath = r->path();
|
||||||
|
|
||||||
|
// add default pages.
|
||||||
|
if (srs_string_ends_with(upath, "/")) {
|
||||||
|
upath += SRS_HTTP_DEFAULT_PAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
string fullpath = dir + "/";
|
||||||
|
|
||||||
|
// remove the virtual directory.
|
||||||
|
srs_assert(entry);
|
||||||
|
size_t pos = entry->pattern.find("/");
|
||||||
|
if (upath.length() > entry->pattern.length() && pos != string::npos) {
|
||||||
|
fullpath += upath.substr(entry->pattern.length() - pos);
|
||||||
|
} else {
|
||||||
|
fullpath += upath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stat current dir, if exists, return error.
|
||||||
|
if (!srs_path_exists(fullpath)) {
|
||||||
|
srs_warn("http miss file=%s, pattern=%s, upath=%s",
|
||||||
|
fullpath.c_str(), entry->pattern.c_str(), upath.c_str());
|
||||||
|
return SrsHttpNotFoundHandler().serve_http(w, r);
|
||||||
|
}
|
||||||
|
srs_trace("http match file=%s, pattern=%s, upath=%s",
|
||||||
|
fullpath.c_str(), entry->pattern.c_str(), upath.c_str());
|
||||||
|
|
||||||
|
// handle file according to its extension.
|
||||||
|
// use vod stream for .flv/.fhv
|
||||||
|
if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) {
|
||||||
|
return serve_flv_file(w, r, fullpath);
|
||||||
|
} else if (srs_string_ends_with(fullpath, ".mp4")) {
|
||||||
|
return serve_mp4_file(w, r, fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// serve common static file.
|
||||||
|
return serve_file(w, r, fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpFileServer::serve_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
// open the target file.
|
||||||
|
SrsFileReader fs;
|
||||||
|
|
||||||
|
if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) {
|
||||||
|
srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t length = fs.filesize();
|
||||||
|
|
||||||
|
// unset the content length to encode in chunked encoding.
|
||||||
|
w->header()->set_content_length(length);
|
||||||
|
|
||||||
|
static std::map<std::string, std::string> _mime;
|
||||||
|
if (_mime.empty()) {
|
||||||
|
_mime[".ts"] = "video/MP2T";
|
||||||
|
_mime[".flv"] = "video/x-flv";
|
||||||
|
_mime[".m4v"] = "video/x-m4v";
|
||||||
|
_mime[".3gpp"] = "video/3gpp";
|
||||||
|
_mime[".3gp"] = "video/3gpp";
|
||||||
|
_mime[".mp4"] = "video/mp4";
|
||||||
|
_mime[".aac"] = "audio/x-aac";
|
||||||
|
_mime[".mp3"] = "audio/mpeg";
|
||||||
|
_mime[".m4a"] = "audio/x-m4a";
|
||||||
|
_mime[".ogg"] = "audio/ogg";
|
||||||
|
// @see hls-m3u8-draft-pantos-http-live-streaming-12.pdf, page 5.
|
||||||
|
_mime[".m3u8"] = "application/vnd.apple.mpegurl"; // application/x-mpegURL
|
||||||
|
_mime[".rss"] = "application/rss+xml";
|
||||||
|
_mime[".json"] = "application/json";
|
||||||
|
_mime[".swf"] = "application/x-shockwave-flash";
|
||||||
|
_mime[".doc"] = "application/msword";
|
||||||
|
_mime[".zip"] = "application/zip";
|
||||||
|
_mime[".rar"] = "application/x-rar-compressed";
|
||||||
|
_mime[".xml"] = "text/xml";
|
||||||
|
_mime[".html"] = "text/html";
|
||||||
|
_mime[".js"] = "text/javascript";
|
||||||
|
_mime[".css"] = "text/css";
|
||||||
|
_mime[".ico"] = "image/x-icon";
|
||||||
|
_mime[".png"] = "image/png";
|
||||||
|
_mime[".jpeg"] = "image/jpeg";
|
||||||
|
_mime[".jpg"] = "image/jpeg";
|
||||||
|
_mime[".gif"] = "image/gif";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
size_t pos;
|
||||||
|
std::string ext = fullpath;
|
||||||
|
if ((pos = ext.rfind(".")) != string::npos) {
|
||||||
|
ext = ext.substr(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mime.find(ext) == _mime.end()) {
|
||||||
|
w->header()->set_content_type("application/octet-stream");
|
||||||
|
} else {
|
||||||
|
w->header()->set_content_type(_mime[ext]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write body.
|
||||||
|
int64_t left = length;
|
||||||
|
if ((ret = copy(w, &fs, r, (int)left)) != ERROR_SUCCESS) {
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("read file=%s size=%d failed, ret=%d", fullpath.c_str(), left, ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return w->final_request();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpFileServer::serve_flv_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath)
|
||||||
|
{
|
||||||
|
std::string start = r->query_get("start");
|
||||||
|
if (start.empty()) {
|
||||||
|
return serve_file(w, r, fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = ::atoi(start.c_str());
|
||||||
|
if (offset <= 0) {
|
||||||
|
return serve_file(w, r, fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return serve_flv_stream(w, r, fullpath, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpFileServer::serve_mp4_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath)
|
||||||
|
{
|
||||||
|
// for flash to request mp4 range in query string.
|
||||||
|
// for example, http://digitalprimates.net/dash/DashTest.html?url=http://dashdemo.edgesuite.net/digitalprimates/nexus/oops-20120802-manifest.mpd
|
||||||
|
std::string range = r->query_get("range");
|
||||||
|
// or, use bytes to request range,
|
||||||
|
// for example, http://dashas.castlabs.com/demo/try.html
|
||||||
|
if (range.empty()) {
|
||||||
|
range = r->query_get("bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
// rollback to serve whole file.
|
||||||
|
size_t pos = string::npos;
|
||||||
|
if (range.empty() || (pos = range.find("-")) == string::npos) {
|
||||||
|
return serve_file(w, r, fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the start in query string
|
||||||
|
int start = 0;
|
||||||
|
if (pos > 0) {
|
||||||
|
start = ::atoi(range.substr(0, pos).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse end in query string.
|
||||||
|
int end = -1;
|
||||||
|
if (pos < range.length() - 1) {
|
||||||
|
end = ::atoi(range.substr(pos + 1).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalid param, serve as whole mp4 file.
|
||||||
|
if (start < 0 || (end != -1 && start > end)) {
|
||||||
|
return serve_file(w, r, fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return serve_mp4_stream(w, r, fullpath, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpFileServer::serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath, int offset)
|
||||||
|
{
|
||||||
|
return serve_file(w, r, fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpFileServer::serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath, int start, int end)
|
||||||
|
{
|
||||||
|
return serve_file(w, r, fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpFileServer::copy(ISrsHttpResponseWriter* w, SrsFileReader* fs, ISrsHttpMessage* r, int size)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
int left = size;
|
||||||
|
char* buf = r->http_ts_send_buffer();
|
||||||
|
|
||||||
|
while (left > 0) {
|
||||||
|
ssize_t nread = -1;
|
||||||
|
int max_read = srs_min(left, SRS_HTTP_TS_SEND_BUFFER_SIZE);
|
||||||
|
if ((ret = fs->read(buf, max_read, &nread)) != ERROR_SUCCESS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
left -= nread;
|
||||||
|
if ((ret = w->write(buf, (int)nread)) != ERROR_SUCCESS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpMuxEntry::SrsHttpMuxEntry()
|
||||||
|
{
|
||||||
|
enabled = true;
|
||||||
|
explicit_match = false;
|
||||||
|
handler = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpMuxEntry::~SrsHttpMuxEntry()
|
||||||
|
{
|
||||||
|
srs_freep(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsHttpMatchHijacker::ISrsHttpMatchHijacker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsHttpMatchHijacker::~ISrsHttpMatchHijacker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpServeMux::SrsHttpServeMux()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpServeMux::~SrsHttpServeMux()
|
||||||
|
{
|
||||||
|
std::map<std::string, SrsHttpMuxEntry*>::iterator it;
|
||||||
|
for (it = entries.begin(); it != entries.end(); ++it) {
|
||||||
|
SrsHttpMuxEntry* entry = it->second;
|
||||||
|
srs_freep(entry);
|
||||||
|
}
|
||||||
|
entries.clear();
|
||||||
|
|
||||||
|
vhosts.clear();
|
||||||
|
hijackers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpServeMux::initialize()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
// TODO: FIXME: implements it.
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsHttpServeMux::hijack(ISrsHttpMatchHijacker* h)
|
||||||
|
{
|
||||||
|
std::vector<ISrsHttpMatchHijacker*>::iterator it = ::find(hijackers.begin(), hijackers.end(), h);
|
||||||
|
if (it != hijackers.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hijackers.push_back(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsHttpServeMux::unhijack(ISrsHttpMatchHijacker* h)
|
||||||
|
{
|
||||||
|
std::vector<ISrsHttpMatchHijacker*>::iterator it = ::find(hijackers.begin(), hijackers.end(), h);
|
||||||
|
if (it == hijackers.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hijackers.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpServeMux::handle(std::string pattern, ISrsHttpHandler* handler)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
srs_assert(handler);
|
||||||
|
|
||||||
|
if (pattern.empty()) {
|
||||||
|
ret = ERROR_HTTP_PATTERN_EMPTY;
|
||||||
|
srs_error("http: empty pattern. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries.find(pattern) != entries.end()) {
|
||||||
|
SrsHttpMuxEntry* exists = entries[pattern];
|
||||||
|
if (exists->explicit_match) {
|
||||||
|
ret = ERROR_HTTP_PATTERN_DUPLICATED;
|
||||||
|
srs_error("http: multiple registrations for %s. ret=%d", pattern.c_str(), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string vhost = pattern;
|
||||||
|
if (pattern.at(0) != '/') {
|
||||||
|
if (pattern.find("/") != string::npos) {
|
||||||
|
vhost = pattern.substr(0, pattern.find("/"));
|
||||||
|
}
|
||||||
|
vhosts[vhost] = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsHttpMuxEntry* entry = new SrsHttpMuxEntry();
|
||||||
|
entry->explicit_match = true;
|
||||||
|
entry->handler = handler;
|
||||||
|
entry->pattern = pattern;
|
||||||
|
entry->handler->entry = entry;
|
||||||
|
|
||||||
|
if (entries.find(pattern) != entries.end()) {
|
||||||
|
SrsHttpMuxEntry* exists = entries[pattern];
|
||||||
|
srs_freep(exists);
|
||||||
|
}
|
||||||
|
entries[pattern] = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpful behavior:
|
||||||
|
// If pattern is /tree/, insert an implicit permanent redirect for /tree.
|
||||||
|
// It can be overridden by an explicit registration.
|
||||||
|
if (pattern != "/" && !pattern.empty() && pattern.at(pattern.length() - 1) == '/') {
|
||||||
|
std::string rpattern = pattern.substr(0, pattern.length() - 1);
|
||||||
|
SrsHttpMuxEntry* entry = NULL;
|
||||||
|
|
||||||
|
// free the exists not explicit entry
|
||||||
|
if (entries.find(rpattern) != entries.end()) {
|
||||||
|
SrsHttpMuxEntry* exists = entries[rpattern];
|
||||||
|
if (!exists->explicit_match) {
|
||||||
|
entry = exists;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create implicit redirect.
|
||||||
|
if (!entry || entry->explicit_match) {
|
||||||
|
srs_freep(entry);
|
||||||
|
|
||||||
|
entry = new SrsHttpMuxEntry();
|
||||||
|
entry->explicit_match = false;
|
||||||
|
entry->handler = new SrsHttpRedirectHandler(pattern, SRS_CONSTS_HTTP_MovedPermanently);
|
||||||
|
entry->pattern = pattern;
|
||||||
|
entry->handler->entry = entry;
|
||||||
|
|
||||||
|
entries[rpattern] = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpServeMux::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
ISrsHttpHandler* h = NULL;
|
||||||
|
if ((ret = find_handler(r, &h)) != ERROR_SUCCESS) {
|
||||||
|
srs_error("find handler failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_assert(h);
|
||||||
|
if ((ret = h->serve_http(w, r)) != ERROR_SUCCESS) {
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("handler serve http failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpServeMux::find_handler(ISrsHttpMessage* r, ISrsHttpHandler** ph)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
// TODO: FIXME: support the path . and ..
|
||||||
|
if (r->url().find("..") != std::string::npos) {
|
||||||
|
ret = ERROR_HTTP_URL_NOT_CLEAN;
|
||||||
|
srs_error("htt url not canonical, url=%s. ret=%d", r->url().c_str(), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = match(r, ph)) != ERROR_SUCCESS) {
|
||||||
|
srs_error("http match handler failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// always hijack.
|
||||||
|
if (!hijackers.empty()) {
|
||||||
|
// notice all hijacker the match failed.
|
||||||
|
std::vector<ISrsHttpMatchHijacker*>::iterator it;
|
||||||
|
for (it = hijackers.begin(); it != hijackers.end(); ++it) {
|
||||||
|
ISrsHttpMatchHijacker* hijacker = *it;
|
||||||
|
if ((ret = hijacker->hijack(r, ph)) != ERROR_SUCCESS) {
|
||||||
|
srs_error("hijacker match failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ph == NULL) {
|
||||||
|
// TODO: FIXME: memory leak.
|
||||||
|
*ph = new SrsHttpNotFoundHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpServeMux::match(ISrsHttpMessage* r, ISrsHttpHandler** ph)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
std::string path = r->path();
|
||||||
|
|
||||||
|
// Host-specific pattern takes precedence over generic ones
|
||||||
|
if (!vhosts.empty() && vhosts.find(r->host()) != vhosts.end()) {
|
||||||
|
path = r->host() + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nb_matched = 0;
|
||||||
|
ISrsHttpHandler* h = NULL;
|
||||||
|
|
||||||
|
std::map<std::string, SrsHttpMuxEntry*>::iterator it;
|
||||||
|
for (it = entries.begin(); it != entries.end(); ++it) {
|
||||||
|
std::string pattern = it->first;
|
||||||
|
SrsHttpMuxEntry* entry = it->second;
|
||||||
|
|
||||||
|
if (!entry->enabled) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path_match(pattern, path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!h || (int)pattern.length() > nb_matched) {
|
||||||
|
nb_matched = (int)pattern.length();
|
||||||
|
h = entry->handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*ph = h;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SrsHttpServeMux::path_match(string pattern, string path)
|
||||||
|
{
|
||||||
|
if (pattern.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = (int)pattern.length();
|
||||||
|
|
||||||
|
// not endswith '/', exactly match.
|
||||||
|
if (pattern.at(n - 1) != '/') {
|
||||||
|
return pattern == path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// endswith '/', match any,
|
||||||
|
// for example, '/api/' match '/api/[N]'
|
||||||
|
if ((int)path.length() >= n) {
|
||||||
|
if (memcmp(pattern.data(), path.data(), n) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsHttpMessage::ISrsHttpMessage()
|
||||||
|
{
|
||||||
|
_http_ts_send_buffer = new char[SRS_HTTP_TS_SEND_BUFFER_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsHttpMessage::~ISrsHttpMessage()
|
||||||
|
{
|
||||||
|
srs_freep(_http_ts_send_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* ISrsHttpMessage::http_ts_send_buffer()
|
||||||
|
{
|
||||||
|
return _http_ts_send_buffer;
|
||||||
|
}
|
||||||
|
|
|
@ -29,4 +29,466 @@
|
||||||
*/
|
*/
|
||||||
#include <srs_core.hpp>
|
#include <srs_core.hpp>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class SrsFileReader;
|
||||||
|
class SrsHttpHeader;
|
||||||
|
class ISrsHttpMessage;
|
||||||
|
class SrsHttpMuxEntry;
|
||||||
|
class ISrsHttpResponseWriter;
|
||||||
|
|
||||||
|
// http specification
|
||||||
|
// CR = <US-ASCII CR, carriage return (13)>
|
||||||
|
#define SRS_HTTP_CR SRS_CONSTS_CR // 0x0D
|
||||||
|
// LF = <US-ASCII LF, linefeed (10)>
|
||||||
|
#define SRS_HTTP_LF SRS_CONSTS_LF // 0x0A
|
||||||
|
// SP = <US-ASCII SP, space (32)>
|
||||||
|
#define SRS_HTTP_SP ' ' // 0x20
|
||||||
|
// HT = <US-ASCII HT, horizontal-tab (9)>
|
||||||
|
#define SRS_HTTP_HT '\x09' // 0x09
|
||||||
|
|
||||||
|
// HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
|
||||||
|
// protocol elements except the entity-body (see appendix 19.3 for
|
||||||
|
// tolerant applications).
|
||||||
|
#define SRS_HTTP_CRLF "\r\n" // 0x0D0A
|
||||||
|
#define SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
|
||||||
|
|
||||||
|
// @see ISrsHttpMessage._http_ts_send_buffer
|
||||||
|
#define SRS_HTTP_TS_SEND_BUFFER_SIZE 4096
|
||||||
|
|
||||||
|
// for ead all of http body, read each time.
|
||||||
|
#define SRS_HTTP_READ_CACHE_BYTES 4096
|
||||||
|
|
||||||
|
// default http listen port.
|
||||||
|
#define SRS_DEFAULT_HTTP_PORT 80
|
||||||
|
|
||||||
|
// for http parser macros
|
||||||
|
#define SRS_CONSTS_HTTP_OPTIONS HTTP_OPTIONS
|
||||||
|
#define SRS_CONSTS_HTTP_GET HTTP_GET
|
||||||
|
#define SRS_CONSTS_HTTP_POST HTTP_POST
|
||||||
|
#define SRS_CONSTS_HTTP_PUT HTTP_PUT
|
||||||
|
#define SRS_CONSTS_HTTP_DELETE HTTP_DELETE
|
||||||
|
|
||||||
|
// helper function: response in json format.
|
||||||
|
extern int srs_http_response_json(ISrsHttpResponseWriter* w, std::string data);
|
||||||
|
|
||||||
|
// get the status text of code.
|
||||||
|
extern std::string srs_generate_http_status_text(int status);
|
||||||
|
|
||||||
|
// bodyAllowedForStatus reports whether a given response status code
|
||||||
|
// permits a body. See RFC2616, section 4.4.
|
||||||
|
extern bool srs_go_http_body_allowd(int status);
|
||||||
|
|
||||||
|
// DetectContentType implements the algorithm described
|
||||||
|
// at http://mimesniff.spec.whatwg.org/ to determine the
|
||||||
|
// Content-Type of the given data. It considers at most the
|
||||||
|
// first 512 bytes of data. DetectContentType always returns
|
||||||
|
// a valid MIME type: if it cannot determine a more specific one, it
|
||||||
|
// returns "application/octet-stream".
|
||||||
|
extern std::string srs_go_http_detect(char* data, int size);
|
||||||
|
|
||||||
|
// state of message
|
||||||
|
enum SrsHttpParseState {
|
||||||
|
SrsHttpParseStateInit = 0,
|
||||||
|
SrsHttpParseStateStart,
|
||||||
|
SrsHttpParseStateHeaderComplete,
|
||||||
|
SrsHttpParseStateMessageComplete
|
||||||
|
};
|
||||||
|
|
||||||
|
// A Header represents the key-value pairs in an HTTP header.
|
||||||
|
class SrsHttpHeader
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::map<std::string, std::string> headers;
|
||||||
|
public:
|
||||||
|
SrsHttpHeader();
|
||||||
|
virtual ~SrsHttpHeader();
|
||||||
|
public:
|
||||||
|
// Add adds the key, value pair to the header.
|
||||||
|
// It appends to any existing values associated with key.
|
||||||
|
virtual void set(std::string key, std::string value);
|
||||||
|
// Get gets the first value associated with the given key.
|
||||||
|
// If there are no values associated with the key, Get returns "".
|
||||||
|
// To access multiple values of a key, access the map directly
|
||||||
|
// with CanonicalHeaderKey.
|
||||||
|
virtual std::string get(std::string key);
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* get the content length. -1 if not set.
|
||||||
|
*/
|
||||||
|
virtual int64_t content_length();
|
||||||
|
/**
|
||||||
|
* set the content length by header "Content-Length"
|
||||||
|
*/
|
||||||
|
virtual void set_content_length(int64_t size);
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* get the content type. empty string if not set.
|
||||||
|
*/
|
||||||
|
virtual std::string content_type();
|
||||||
|
/**
|
||||||
|
* set the content type by header "Content-Type"
|
||||||
|
*/
|
||||||
|
virtual void set_content_type(std::string ct);
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* write all headers to string stream.
|
||||||
|
*/
|
||||||
|
virtual void write(std::stringstream& ss);
|
||||||
|
};
|
||||||
|
|
||||||
|
// A ResponseWriter interface is used by an HTTP handler to
|
||||||
|
// construct an HTTP response.
|
||||||
|
// Usage 1, response with specified length content:
|
||||||
|
// ISrsHttpResponseWriter* w; // create or get response.
|
||||||
|
// std::string msg = "Hello, HTTP!";
|
||||||
|
// w->header()->set_content_type("text/plain; charset=utf-8");
|
||||||
|
// w->header()->set_content_length(msg.length());
|
||||||
|
// w->write_header(SRS_CONSTS_HTTP_OK);
|
||||||
|
// w->write((char*)msg.data(), (int)msg.length());
|
||||||
|
// w->final_request(); // optional flush.
|
||||||
|
// Usage 2, response with HTTP code only, zero content length.
|
||||||
|
// ISrsHttpResponseWriter* w; // create or get response.
|
||||||
|
// w->header()->set_content_length(0);
|
||||||
|
// w->write_header(SRS_CONSTS_HTTP_OK);
|
||||||
|
// w->final_request();
|
||||||
|
// Usage 3, response in chunked encoding.
|
||||||
|
// ISrsHttpResponseWriter* w; // create or get response.
|
||||||
|
// std::string msg = "Hello, HTTP!";
|
||||||
|
// w->header()->set_content_type("application/octet-stream");
|
||||||
|
// w->write_header(SRS_CONSTS_HTTP_OK);
|
||||||
|
// w->write((char*)msg.data(), (int)msg.length());
|
||||||
|
// w->write((char*)msg.data(), (int)msg.length());
|
||||||
|
// w->write((char*)msg.data(), (int)msg.length());
|
||||||
|
// w->write((char*)msg.data(), (int)msg.length());
|
||||||
|
// w->final_request(); // required to end the chunked and flush.
|
||||||
|
class ISrsHttpResponseWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsHttpResponseWriter();
|
||||||
|
virtual ~ISrsHttpResponseWriter();
|
||||||
|
public:
|
||||||
|
// when chunked mode,
|
||||||
|
// final the request to complete the chunked encoding.
|
||||||
|
// for no-chunked mode,
|
||||||
|
// final to send request, for example, content-length is 0.
|
||||||
|
virtual int final_request() = 0;
|
||||||
|
|
||||||
|
// Header returns the header map that will be sent by WriteHeader.
|
||||||
|
// Changing the header after a call to WriteHeader (or Write) has
|
||||||
|
// no effect.
|
||||||
|
virtual SrsHttpHeader* header() = 0;
|
||||||
|
|
||||||
|
// Write writes the data to the connection as part of an HTTP reply.
|
||||||
|
// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
|
||||||
|
// before writing the data. If the Header does not contain a
|
||||||
|
// Content-Type line, Write adds a Content-Type set to the result of passing
|
||||||
|
// the initial 512 bytes of written data to DetectContentType.
|
||||||
|
// @param data, the data to send. NULL to flush header only.
|
||||||
|
virtual int write(char* data, int size) = 0;
|
||||||
|
|
||||||
|
// WriteHeader sends an HTTP response header with status code.
|
||||||
|
// If WriteHeader is not called explicitly, the first call to Write
|
||||||
|
// will trigger an implicit WriteHeader(http.StatusOK).
|
||||||
|
// Thus explicit calls to WriteHeader are mainly used to
|
||||||
|
// send error codes.
|
||||||
|
// @remark, user must set header then write or write_header.
|
||||||
|
virtual void write_header(int code) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the reader interface for http response.
|
||||||
|
*/
|
||||||
|
class ISrsHttpResponseReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsHttpResponseReader();
|
||||||
|
virtual ~ISrsHttpResponseReader();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* whether response read EOF.
|
||||||
|
*/
|
||||||
|
virtual bool eof() = 0;
|
||||||
|
/**
|
||||||
|
* read from the response body.
|
||||||
|
* @param data, the buffer to read data buffer to.
|
||||||
|
* @param nb_data, the max size of data buffer.
|
||||||
|
* @param nb_read, the actual read size of bytes. NULL to ignore.
|
||||||
|
* @remark when eof(), return error.
|
||||||
|
*/
|
||||||
|
virtual int read(char* data, int nb_data, int* nb_read) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Objects implementing the Handler interface can be
|
||||||
|
// registered to serve a particular path or subtree
|
||||||
|
// in the HTTP server.
|
||||||
|
//
|
||||||
|
// ServeHTTP should write reply headers and data to the ResponseWriter
|
||||||
|
// and then return. Returning signals that the request is finished
|
||||||
|
// and that the HTTP server can move on to the next request on
|
||||||
|
// the connection.
|
||||||
|
class ISrsHttpHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SrsHttpMuxEntry* entry;
|
||||||
|
public:
|
||||||
|
ISrsHttpHandler();
|
||||||
|
virtual ~ISrsHttpHandler();
|
||||||
|
public:
|
||||||
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Redirect to a fixed URL
|
||||||
|
class SrsHttpRedirectHandler : public ISrsHttpHandler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::string url;
|
||||||
|
int code;
|
||||||
|
public:
|
||||||
|
SrsHttpRedirectHandler(std::string u, int c);
|
||||||
|
virtual ~SrsHttpRedirectHandler();
|
||||||
|
public:
|
||||||
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
|
};
|
||||||
|
|
||||||
|
// NotFound replies to the request with an HTTP 404 not found error.
|
||||||
|
class SrsHttpNotFoundHandler : public ISrsHttpHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SrsHttpNotFoundHandler();
|
||||||
|
virtual ~SrsHttpNotFoundHandler();
|
||||||
|
public:
|
||||||
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
|
};
|
||||||
|
|
||||||
|
// FileServer returns a handler that serves HTTP requests
|
||||||
|
// with the contents of the file system rooted at root.
|
||||||
|
//
|
||||||
|
// To use the operating system's file system implementation,
|
||||||
|
// use http.Dir:
|
||||||
|
//
|
||||||
|
// http.Handle("/", SrsHttpFileServer("/tmp"))
|
||||||
|
// http.Handle("/", SrsHttpFileServer("static-dir"))
|
||||||
|
class SrsHttpFileServer : public ISrsHttpHandler
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::string dir;
|
||||||
|
public:
|
||||||
|
SrsHttpFileServer(std::string root_dir);
|
||||||
|
virtual ~SrsHttpFileServer();
|
||||||
|
public:
|
||||||
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* serve the file by specified path
|
||||||
|
*/
|
||||||
|
virtual int serve_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath);
|
||||||
|
virtual int serve_flv_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath);
|
||||||
|
virtual int serve_mp4_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath);
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* when access flv file with x.flv?start=xxx
|
||||||
|
*/
|
||||||
|
virtual int serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath, int offset);
|
||||||
|
/**
|
||||||
|
* when access mp4 file with x.mp4?range=start-end
|
||||||
|
* @param start the start offset in bytes.
|
||||||
|
* @param end the end offset in bytes. -1 to end of file.
|
||||||
|
* @remark response data in [start, end].
|
||||||
|
*/
|
||||||
|
virtual int serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath, int start, int end);
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* copy the fs to response writer in size bytes.
|
||||||
|
*/
|
||||||
|
virtual int copy(ISrsHttpResponseWriter* w, SrsFileReader* fs, ISrsHttpMessage* r, int size);
|
||||||
|
};
|
||||||
|
|
||||||
|
// the mux entry for server mux.
|
||||||
|
// the matcher info, for example, the pattern and handler.
|
||||||
|
class SrsHttpMuxEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool explicit_match;
|
||||||
|
ISrsHttpHandler* handler;
|
||||||
|
std::string pattern;
|
||||||
|
bool enabled;
|
||||||
|
public:
|
||||||
|
SrsHttpMuxEntry();
|
||||||
|
virtual ~SrsHttpMuxEntry();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the hijacker for http pattern match.
|
||||||
|
*/
|
||||||
|
class ISrsHttpMatchHijacker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsHttpMatchHijacker();
|
||||||
|
virtual ~ISrsHttpMatchHijacker();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* when match the request failed, no handler to process request.
|
||||||
|
* @param request the http request message to match the handler.
|
||||||
|
* @param ph the already matched handler, hijack can rewrite it.
|
||||||
|
*/
|
||||||
|
virtual int hijack(ISrsHttpMessage* request, ISrsHttpHandler** ph) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ServeMux is an HTTP request multiplexer.
|
||||||
|
// It matches the URL of each incoming request against a list of registered
|
||||||
|
// patterns and calls the handler for the pattern that
|
||||||
|
// most closely matches the URL.
|
||||||
|
//
|
||||||
|
// Patterns name fixed, rooted paths, like "/favicon.ico",
|
||||||
|
// or rooted subtrees, like "/images/" (note the trailing slash).
|
||||||
|
// Longer patterns take precedence over shorter ones, so that
|
||||||
|
// if there are handlers registered for both "/images/"
|
||||||
|
// and "/images/thumbnails/", the latter handler will be
|
||||||
|
// called for paths beginning "/images/thumbnails/" and the
|
||||||
|
// former will receive requests for any other paths in the
|
||||||
|
// "/images/" subtree.
|
||||||
|
//
|
||||||
|
// Note that since a pattern ending in a slash names a rooted subtree,
|
||||||
|
// the pattern "/" matches all paths not matched by other registered
|
||||||
|
// patterns, not just the URL with Path == "/".
|
||||||
|
//
|
||||||
|
// Patterns may optionally begin with a host name, restricting matches to
|
||||||
|
// URLs on that host only. Host-specific patterns take precedence over
|
||||||
|
// general patterns, so that a handler might register for the two patterns
|
||||||
|
// "/codesearch" and "codesearch.google.com/" without also taking over
|
||||||
|
// requests for "http://www.google.com/".
|
||||||
|
//
|
||||||
|
// ServeMux also takes care of sanitizing the URL request path,
|
||||||
|
// redirecting any request containing . or .. elements to an
|
||||||
|
// equivalent .- and ..-free URL.
|
||||||
|
class SrsHttpServeMux
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// the pattern handler, to handle the http request.
|
||||||
|
std::map<std::string, SrsHttpMuxEntry*> entries;
|
||||||
|
// the vhost handler.
|
||||||
|
// when find the handler to process the request,
|
||||||
|
// append the matched vhost when pattern not starts with /,
|
||||||
|
// for example, for pattern /live/livestream.flv of vhost ossrs.net,
|
||||||
|
// the path will rewrite to ossrs.net/live/livestream.flv
|
||||||
|
std::map<std::string, ISrsHttpHandler*> vhosts;
|
||||||
|
// all hijackers for http match.
|
||||||
|
// for example, the hstrs(http stream trigger rtmp source)
|
||||||
|
// can hijack and install handler when request incoming and no handler.
|
||||||
|
std::vector<ISrsHttpMatchHijacker*> hijackers;
|
||||||
|
public:
|
||||||
|
SrsHttpServeMux();
|
||||||
|
virtual ~SrsHttpServeMux();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* initialize the http serve mux.
|
||||||
|
*/
|
||||||
|
virtual int initialize();
|
||||||
|
/**
|
||||||
|
* hijack the http match.
|
||||||
|
*/
|
||||||
|
virtual void hijack(ISrsHttpMatchHijacker* h);
|
||||||
|
virtual void unhijack(ISrsHttpMatchHijacker* h);
|
||||||
|
public:
|
||||||
|
// Handle registers the handler for the given pattern.
|
||||||
|
// If a handler already exists for pattern, Handle panics.
|
||||||
|
virtual int handle(std::string pattern, ISrsHttpHandler* handler);
|
||||||
|
// interface ISrsHttpHandler
|
||||||
|
public:
|
||||||
|
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||||
|
private:
|
||||||
|
virtual int find_handler(ISrsHttpMessage* r, ISrsHttpHandler** ph);
|
||||||
|
virtual int match(ISrsHttpMessage* r, ISrsHttpHandler** ph);
|
||||||
|
virtual bool path_match(std::string pattern, std::string path);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// The field semantics differ slightly between client and server
|
||||||
|
// usage. In addition to the notes on the fields below, see the
|
||||||
|
// documentation for Request.Write and RoundTripper.
|
||||||
|
/**
|
||||||
|
* the http message, request or response.
|
||||||
|
*/
|
||||||
|
class ISrsHttpMessage
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* use a buffer to read and send ts file.
|
||||||
|
*/
|
||||||
|
// TODO: FIXME: remove it.
|
||||||
|
char* _http_ts_send_buffer;
|
||||||
|
public:
|
||||||
|
ISrsHttpMessage();
|
||||||
|
virtual ~ISrsHttpMessage();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* the http request level cache.
|
||||||
|
*/
|
||||||
|
virtual char* http_ts_send_buffer();
|
||||||
|
public:
|
||||||
|
virtual u_int8_t method() = 0;
|
||||||
|
virtual u_int16_t status_code() = 0;
|
||||||
|
/**
|
||||||
|
* method helpers.
|
||||||
|
*/
|
||||||
|
virtual std::string method_str() = 0;
|
||||||
|
virtual bool is_http_get() = 0;
|
||||||
|
virtual bool is_http_put() = 0;
|
||||||
|
virtual bool is_http_post() = 0;
|
||||||
|
virtual bool is_http_delete() = 0;
|
||||||
|
virtual bool is_http_options() = 0;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* whether should keep the connection alive.
|
||||||
|
*/
|
||||||
|
virtual bool is_keep_alive() = 0;
|
||||||
|
/**
|
||||||
|
* the uri contains the host and path.
|
||||||
|
*/
|
||||||
|
virtual std::string uri() = 0;
|
||||||
|
/**
|
||||||
|
* the url maybe the path.
|
||||||
|
*/
|
||||||
|
virtual std::string url() = 0;
|
||||||
|
virtual std::string host() = 0;
|
||||||
|
virtual std::string path() = 0;
|
||||||
|
virtual std::string ext() = 0;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* read body to string.
|
||||||
|
* @remark for small http body.
|
||||||
|
*/
|
||||||
|
virtual int body_read_all(std::string& body) = 0;
|
||||||
|
/**
|
||||||
|
* get the body reader, to read one by one.
|
||||||
|
* @remark when body is very large, or chunked, use this.
|
||||||
|
*/
|
||||||
|
virtual ISrsHttpResponseReader* body_reader() = 0;
|
||||||
|
/**
|
||||||
|
* the content length, -1 for chunked or not set.
|
||||||
|
*/
|
||||||
|
virtual int64_t content_length() = 0;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* get the param in query string,
|
||||||
|
* for instance, query is "start=100&end=200",
|
||||||
|
* 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;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue