winlin

refine http

... ... @@ -409,7 +409,7 @@ LIBS_OBJS="${MODULE_OBJS[@]}"
if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
MODULE_ID="MAIN"
MODULE_DEPENDS=("CORE" "KERNEL" "RTMP" "APP")
ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot})
ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibHttpParserRoot})
MODULE_FILES=("srs_main_server")
MAIN_INCS="src/main"; MODULE_DIR=${MAIN_INCS} . auto/modules.sh
MAIN_OBJS="${MODULE_OBJS[@]}"
... ...
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 3.1.1, 2015-01-29T11:22:06. -->
<!-- Written by QtCreator 3.1.1, 2015-03-05T20:44:44. -->
<qtcreator>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
... ... @@ -56,12 +56,12 @@
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{fa2d28f9-85de-4a75-8e79-69d805f974bf}</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{fdda5a74-8ef6-4e67-b28c-c5be6c667578}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/winlin/git/simple-rtmp-server/trunk/src/build-qt-Desktop-Debug</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/winlin/git/simple-rtmp-server/trunk/ide/build-srs-qt-Desktop-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
... ... @@ -119,7 +119,66 @@
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/winlin/git/simple-rtmp-server/trunk/ide/build-srs-qt-Desktop-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">2</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
... ... @@ -172,13 +231,13 @@
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">srs-qt</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">srs-qt2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/winlin/git/simple-rtmp-server/trunk/ide/srs_qt/srs-qt.pro</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments">-c console.conf</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">srs-qt.pro</value>
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal">true</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory">/home/winlin/srs</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
... ...
... ... @@ -904,6 +904,7 @@ int SrsHttpResponseReader::read(int max, std::string& data)
SrsHttpMessage::SrsHttpMessage(SrsStSocket* io)
{
chunked = false;
_uri = new SrsHttpUri();
_body = new SrsHttpResponseReader(this, io);
_http_ts_send_buffer = new char[__SRS_HTTP_TS_SEND_BUFFER_SIZE];
... ... @@ -924,6 +925,11 @@ int SrsHttpMessage::initialize(string url, http_parser* header, string body, vec
_header = *header;
_headers = headers;
// whether chunked.
std::string transfer_encoding = get_request_header("Transfer-Encoding");
chunked = (transfer_encoding == "chunked");
// TODO: FIXME: remove it, use fast buffer instead.
if (!body.empty()) {
_body->append((char*)body.data(), (int)body.length());
}
... ... @@ -1031,6 +1037,11 @@ bool SrsHttpMessage::is_http_options()
return _header.method == SRS_CONSTS_HTTP_OPTIONS;
}
bool SrsHttpMessage::is_chunked()
{
return chunked;
}
string SrsHttpMessage::uri()
{
std::string uri = _uri->get_schema();
... ... @@ -1104,6 +1115,11 @@ int SrsHttpMessage::body_read_all(string body)
return ret;
}
ISrsHttpResponseReader* SrsHttpMessage::body_reader()
{
return _body;
}
int64_t SrsHttpMessage::content_length()
{
return _header.content_length;
... ... @@ -1258,6 +1274,11 @@ int SrsHttpParser::parse_message_imp(SrsStSocket* skt)
return ret;
}
}
// parse last header.
if (!filed_name.empty() && !field_value.empty()) {
headers.push_back(std::make_pair(filed_name, field_value));
}
// when parse completed, cache the left body.
if (nread && nparsed < nread) {
... ... @@ -1341,7 +1362,7 @@ int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t l
obj->filed_name.append(at, (int)length);
}
srs_trace("Header field(%d bytes): %.*s", (int)length, (int)length, at);
srs_info("Header field(%d bytes): %.*s", (int)length, (int)length, at);
return 0;
}
... ... @@ -1355,7 +1376,7 @@ int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t l
}
obj->expect_filed_name = false;
srs_trace("Header value(%d bytes): %.*s", (int)length, (int)length, at);
srs_info("Header value(%d bytes): %.*s", (int)length, (int)length, at);
return 0;
}
... ...
... ... @@ -49,6 +49,7 @@ class SrsFileReader;
class SrsSimpleBuffer;
class SrsHttpMuxEntry;
class ISrsHttpResponseWriter;
class SrsFastBuffer;
// http specification
// CR = <US-ASCII CR, carriage return (13)>
... ... @@ -442,6 +443,10 @@ private:
*/
SrsHttpResponseReader* _body;
/**
* whether the body is chunked.
*/
bool chunked;
/**
* uri parser
*/
SrsHttpUri* _uri;
... ... @@ -474,12 +479,14 @@ public:
virtual bool is_http_post();
virtual bool is_http_delete();
virtual bool is_http_options();
virtual bool is_chunked();
virtual std::string uri();
virtual std::string url();
virtual std::string host();
virtual std::string path();
public:
virtual int body_read_all(std::string body);
virtual ISrsHttpResponseReader* body_reader();
virtual int64_t content_length();
/**
* get the param in query string,
... ... @@ -502,6 +509,8 @@ class SrsHttpParser
private:
http_parser_settings settings;
http_parser parser;
// the global parse buffer.
SrsFastBuffer* fbuffer;
private:
// http parse data, reset before parse message.
bool expect_filed_name;
... ...
... ... @@ -45,6 +45,7 @@ SrsHttpClient::SrsHttpClient()
connected = false;
stfd = NULL;
parser = NULL;
skt = NULL;
}
SrsHttpClient::~SrsHttpClient()
... ... @@ -86,10 +87,8 @@ int SrsHttpClient::post(SrsHttpUri* uri, string req, int& status_code, string& r
<< __SRS_HTTP_CRLF
<< req;
SrsStSocket skt(stfd);
std::string data = ss.str();
if ((ret = skt.write((void*)data.c_str(), data.length(), NULL)) != ERROR_SUCCESS) {
if ((ret = skt->write((void*)data.c_str(), data.length(), NULL)) != ERROR_SUCCESS) {
// disconnect when error.
disconnect();
... ... @@ -98,7 +97,7 @@ int SrsHttpClient::post(SrsHttpUri* uri, string req, int& status_code, string& r
}
SrsHttpMessage* msg = NULL;
if ((ret = parser->parse_message(&skt, &msg)) != ERROR_SUCCESS) {
if ((ret = parser->parse_message(skt, &msg)) != ERROR_SUCCESS) {
srs_error("parse http post response failed. ret=%d", ret);
return ret;
}
... ... @@ -119,11 +118,67 @@ int SrsHttpClient::post(SrsHttpUri* uri, string req, int& status_code, string& r
return ret;
}
int SrsHttpClient::get(SrsHttpUri* uri, std::string req, SrsHttpMessage** ppmsg)
{
*ppmsg = NULL;
int ret = ERROR_SUCCESS;
if (!parser) {
parser = new SrsHttpParser();
if ((ret = parser->initialize(HTTP_RESPONSE)) != ERROR_SUCCESS) {
srs_error("initialize parser failed. ret=%d", ret);
return ret;
}
}
if ((ret = connect(uri)) != ERROR_SUCCESS) {
srs_warn("http connect server failed. ret=%d", ret);
return ret;
}
// send POST request to uri
// GET %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s
std::stringstream ss;
ss << "GET " << uri->get_path() << " "
<< "HTTP/1.1" << __SRS_HTTP_CRLF
<< "Host: " << uri->get_host() << __SRS_HTTP_CRLF
<< "Connection: Keep-Alive" << __SRS_HTTP_CRLF
<< "Content-Length: " << std::dec << req.length() << __SRS_HTTP_CRLF
<< "User-Agent: " << RTMP_SIG_SRS_NAME << RTMP_SIG_SRS_VERSION << __SRS_HTTP_CRLF
<< "Content-Type: application/json" << __SRS_HTTP_CRLF
<< __SRS_HTTP_CRLF
<< req;
std::string data = ss.str();
if ((ret = skt->write((void*)data.c_str(), data.length(), NULL)) != ERROR_SUCCESS) {
// disconnect when error.
disconnect();
srs_error("write http get failed. ret=%d", ret);
return ret;
}
SrsHttpMessage* msg = NULL;
if ((ret = parser->parse_message(skt, &msg)) != ERROR_SUCCESS) {
srs_error("parse http post response failed. ret=%d", ret);
return ret;
}
srs_assert(msg);
*ppmsg = msg;
srs_info("parse http get response success.");
return ret;
}
void SrsHttpClient::disconnect()
{
connected = false;
srs_close_stfd(stfd);
srs_freep(skt);
}
int SrsHttpClient::connect(SrsHttpUri* uri)
... ... @@ -149,6 +204,8 @@ int SrsHttpClient::connect(SrsHttpUri* uri)
srs_info("connect to server success. http url=%s, server=%s, port=%d",
uri->get_url(), uri->get_host(), uri->get_port());
srs_assert(!skt);
skt = new SrsStSocket(stfd);
connected = true;
return ret;
... ...
... ... @@ -37,6 +37,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
class SrsHttpUri;
class SrsHttpParser;
class SrsHttpMessage;
class SrsStSocket;
/**
* http client to GET/POST/PUT/DELETE uri
... ... @@ -46,6 +48,7 @@ class SrsHttpClient
private:
bool connected;
st_netfd_t stfd;
SrsStSocket* skt;
SrsHttpParser* parser;
public:
SrsHttpClient();
... ... @@ -53,11 +56,17 @@ public:
public:
/**
* to post data to the uri.
* @param req the data post to uri.
* @param req the data post to uri. empty string to ignore.
* @param status_code the output status code response by server.
* @param res output the response data from server.
*/
virtual int post(SrsHttpUri* uri, std::string req, int& status_code, std::string& res);
/**
* to get data from the uri.
* @param req the data post to uri. empty string to ignore.
* @param ppmsg output the http message to read the response.
*/
virtual int get(SrsHttpUri* uri, std::string req, SrsHttpMessage** ppmsg);
private:
virtual void disconnect();
virtual int connect(SrsHttpUri* uri);
... ...
... ... @@ -131,7 +131,7 @@ int SrsRtpConn::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf)
SrsRtspAudioCache::SrsRtspAudioCache()
{
dts = NULL;
dts = 0;
audio_samples = NULL;
payload = NULL;
}
... ...
... ... @@ -312,6 +312,8 @@ int run()
return run_master();
}
#include <srs_app_http.hpp>
#include <srs_app_http_client.hpp>
int run_master()
{
int ret = ERROR_SUCCESS;
... ... @@ -327,6 +329,22 @@ int run_master()
if ((ret = _srs_server->initialize_st()) != ERROR_SUCCESS) {
return ret;
}
/*SrsHttpClient client;
SrsHttpUri uri;
if ((ret = uri.initialize("http://ossrs.net:8081/live/livestream.flv")) != ERROR_SUCCESS) {
return ret;
}
SrsHttpMessage* msg = NULL;
if ((ret = client.get(&uri, "", &msg)) != ERROR_SUCCESS) {
return ret;
}
for (;;) {
ISrsHttpResponseReader* br = msg->body_reader();
std::string data;
if ((ret = br->read(0, data)) != ERROR_SUCCESS) {
return ret;
}
}*/
if ((ret = _srs_server->listen()) != ERROR_SUCCESS) {
return ret;
... ...
... ... @@ -130,6 +130,7 @@ public:
* @param v true to ename merged read.
* @param handler the handler when merge read is enabled.
* @see https://github.com/winlinvip/simple-rtmp-server/issues/241
* @remark the merged read is optional, ignore if not specifies.
*/
virtual void set_merge_read(bool v, IMergeReadHandler* handler);
#endif
... ...