From ea1e015a4e3301e0040436f1802cd9ec33ed617b Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 4 May 2015 18:11:52 +0800 Subject: [PATCH] fix the http read chunked encoding bug. --- trunk/src/app/srs_app_caster_flv.cpp | 23 ++++++++++-- trunk/src/app/srs_app_caster_flv.hpp | 10 +++++ trunk/src/app/srs_app_http.cpp | 56 +++++++++++++++------------- trunk/src/app/srs_app_http.hpp | 2 + trunk/src/app/srs_app_http_conn.cpp | 31 ++++++++++++--- trunk/src/app/srs_app_http_conn.hpp | 14 +++++++ trunk/src/app/srs_app_server.cpp | 2 +- 7 files changed, 104 insertions(+), 34 deletions(-) diff --git a/trunk/src/app/srs_app_caster_flv.cpp b/trunk/src/app/srs_app_caster_flv.cpp index e57d0a044..96854a59a 100644 --- a/trunk/src/app/srs_app_caster_flv.cpp +++ b/trunk/src/app/srs_app_caster_flv.cpp @@ -37,6 +37,8 @@ using namespace std; #include #include +#define SRS_HTTP_FLV_STREAM_BUFFER 4096 + SrsAppCasterFlv::SrsAppCasterFlv(SrsConfDirective* c) { http_mux = new SrsHttpServeMux(); @@ -62,7 +64,7 @@ int SrsAppCasterFlv::on_tcp_client(st_netfd_t stfd) { int ret = ERROR_SUCCESS; - SrsHttpConn* conn = new SrsHttpConn(this, stfd, http_mux); + SrsHttpConn* conn = new SrsDynamicHttpConn(this, stfd, http_mux); conns.push_back(conn); if ((ret = conn->start()) != ERROR_SUCCESS) { @@ -79,7 +81,7 @@ void SrsAppCasterFlv::remove(SrsConnection* c) conns.erase(it); } } -#define SRS_HTTP_FLV_STREAM_BUFFER 4096 + int SrsAppCasterFlv::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r) { int ret = ERROR_SUCCESS; @@ -95,10 +97,25 @@ int SrsAppCasterFlv::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r) if ((ret = rr->read(buffer, SRS_HTTP_FLV_STREAM_BUFFER, &nb_read)) != ERROR_SUCCESS) { return ret; } - srs_trace("flv: read %dB from %s", nb_read, r->path().c_str()); + //srs_trace("flv: read %dB from %s", nb_read, r->path().c_str()); } return ret; } +SrsDynamicHttpConn::SrsDynamicHttpConn(IConnectionManager* cm, st_netfd_t fd, SrsHttpServeMux* m) + : SrsHttpConn(cm, fd, m) +{ +} + +SrsDynamicHttpConn::~SrsDynamicHttpConn() +{ +} + +int SrsDynamicHttpConn::on_got_http_message(SrsHttpMessage* msg) +{ + int ret = ERROR_SUCCESS; + return ret; +} + #endif diff --git a/trunk/src/app/srs_app_caster_flv.hpp b/trunk/src/app/srs_app_caster_flv.hpp index fb092f5b2..fc4edd83b 100644 --- a/trunk/src/app/srs_app_caster_flv.hpp +++ b/trunk/src/app/srs_app_caster_flv.hpp @@ -43,6 +43,7 @@ class SrsHttpConn; #include #include #include +#include class SrsAppCasterFlv : virtual public ISrsTcpHandler , virtual public IConnectionManager, virtual public ISrsHttpHandler @@ -67,6 +68,15 @@ public: virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r); }; +class SrsDynamicHttpConn : public SrsHttpConn +{ +public: + SrsDynamicHttpConn(IConnectionManager* cm, st_netfd_t fd, SrsHttpServeMux* m); + virtual ~SrsDynamicHttpConn(); +public: + virtual int on_got_http_message(SrsHttpMessage* msg); +}; + #endif #endif diff --git a/trunk/src/app/srs_app_http.cpp b/trunk/src/app/srs_app_http.cpp index f038f5f71..27979de4f 100644 --- a/trunk/src/app/srs_app_http.cpp +++ b/trunk/src/app/srs_app_http.cpp @@ -905,6 +905,7 @@ int SrsHttpResponseReader::initialize(SrsFastBuffer* body) { int ret = ERROR_SUCCESS; + nb_chunk = 0; nb_left_chunk = 0; nb_total_read = 0; buffer = body; @@ -999,33 +1000,35 @@ int SrsHttpResponseReader::read_chunked(char* data, int nb_data, int* nb_read) } // all bytes in chunk is left now. - nb_left_chunk = ilength; + nb_chunk = nb_left_chunk = ilength; } - // left bytes in chunk, read some. - srs_assert(nb_left_chunk); - - int nb_bytes = srs_min(nb_left_chunk, nb_data); - ret = read_specified(data, nb_bytes, &nb_bytes); - - // the nb_bytes used for output already read size of bytes. - if (nb_read) { - *nb_read = nb_bytes; - } - nb_left_chunk -= nb_bytes; - - // error or still left bytes in chunk, ignore and read in future. - if (nb_left_chunk > 0 || (ret != ERROR_SUCCESS)) { - return ret; - } - srs_info("http: read %d bytes of chunk", nb_bytes); - - // read payload when length specifies some payload. - if (nb_left_chunk <= 0) { + if (nb_chunk <= 0) { + // for the last chunk, eof. is_eof = true; + } else { + // for not the last chunk, there must always exists bytes. + // left bytes in chunk, read some. + srs_assert(nb_left_chunk); + + int nb_bytes = srs_min(nb_left_chunk, nb_data); + ret = read_specified(data, nb_bytes, &nb_bytes); + + // the nb_bytes used for output already read size of bytes. + if (nb_read) { + *nb_read = nb_bytes; + } + nb_left_chunk -= nb_bytes; + srs_info("http: read %d bytes of chunk", nb_bytes); + + // error or still left bytes in chunk, ignore and read in future. + if (nb_left_chunk > 0 || (ret != ERROR_SUCCESS)) { + return ret; + } + srs_info("http: read total chunk %dB", nb_chunk); } - // the CRLF of chunk payload end. + // for both the last or not, the CRLF of chunk payload end. if ((ret = buffer->grow(skt, 2)) != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret)) { srs_error("read EOF of chunk from server failed. ret=%d", ret); @@ -1064,9 +1067,12 @@ int SrsHttpResponseReader::read_specified(char* data, int nb_data, int* nb_read) // increase the total read to determine whether EOF. nb_total_read += nb_bytes; - // when read completed, eof. - if (nb_total_read >= (int)owner->content_length()) { - is_eof = true; + // for not chunked + if (!owner->is_chunked()) { + // when read completed, eof. + if (nb_total_read >= (int)owner->content_length()) { + is_eof = true; + } } return ret; diff --git a/trunk/src/app/srs_app_http.hpp b/trunk/src/app/srs_app_http.hpp index 7c2e1c938..90344751b 100644 --- a/trunk/src/app/srs_app_http.hpp +++ b/trunk/src/app/srs_app_http.hpp @@ -436,6 +436,8 @@ private: bool is_eof; // the left bytes in chunk. int nb_left_chunk; + // the number of bytes of current chunk. + int nb_chunk; // already read total bytes. int64_t nb_total_read; public: diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index c6f4b94b5..21eb95511 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -1398,11 +1398,8 @@ int SrsHttpConn::do_cycle() // always free it in this scope. SrsAutoFree(SrsHttpMessage, req); - // TODO: FIXME: use the post body. - std::string res; - - // get response body. - if ((ret = req->body_read_all(res)) != ERROR_SUCCESS) { + // may should discard the body. + if ((ret = on_got_http_message(req)) != ERROR_SUCCESS) { return ret; } @@ -1434,5 +1431,29 @@ int SrsHttpConn::process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r) return ret; } +SrsStaticHttpConn::SrsStaticHttpConn(IConnectionManager* cm, st_netfd_t fd, SrsHttpServeMux* m) + : SrsHttpConn(cm, fd, m) +{ +} + +SrsStaticHttpConn::~SrsStaticHttpConn() +{ +} + +int SrsStaticHttpConn::on_got_http_message(SrsHttpMessage* msg) +{ + int ret = ERROR_SUCCESS; + + // TODO: FIXME: use the post body. + std::string res; + + // get response body. + if ((ret = msg->body_read_all(res)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + #endif diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index 63f87a5ff..5b4bf62d5 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -388,10 +388,24 @@ public: virtual void cleanup(); protected: virtual int do_cycle(); +protected: + // when got http message, + // 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. + virtual int on_got_http_message(SrsHttpMessage* msg) = 0; private: virtual int process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r); }; +class SrsStaticHttpConn : public SrsHttpConn +{ +public: + SrsStaticHttpConn(IConnectionManager* cm, st_netfd_t fd, SrsHttpServeMux* m); + virtual ~SrsStaticHttpConn(); +public: + virtual int on_got_http_message(SrsHttpMessage* msg); +}; + #endif #endif diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 851c8023c..9b06c8a9d 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -1163,7 +1163,7 @@ int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd) #endif } else if (type == SrsListenerHttpStream) { #ifdef SRS_AUTO_HTTP_SERVER - conn = new SrsHttpConn(this, client_stfd, &http_stream_mux->mux); + conn = new SrsStaticHttpConn(this, client_stfd, &http_stream_mux->mux); #else srs_warn("close http client for server not support http-server"); srs_close_stfd(client_stfd);