diff --git a/README.md b/README.md
index 8c1f6aad7..61672708a 100755
--- a/README.md
+++ b/README.md
@@ -337,6 +337,7 @@ Remark:
## History
+* v2.0, 2017-04-30, Fix [#636][bug #636], FD leak for requesting empty HTTP stream. 2.0.241
* v2.0, 2017-04-23, Fix [#851][bug #851], HTTP API support number of video frames for FPS. 2.0.240
* v2.0, 2017-04-18, [2.0 release1(2.0.239)][r2.0r1] released. 86515 lines.
* v2.0, 2017-04-18, Fix [#848][bug #848], crash at HTTP fast buffer grow. 2.0.239
@@ -1293,6 +1294,7 @@ Winlin
[bug #844]: https://github.com/ossrs/srs/issues/844
[bug #848]: https://github.com/ossrs/srs/issues/848
[bug #851]: https://github.com/ossrs/srs/issues/851
+[bug #636]: https://github.com/ossrs/srs/issues/636
[bug #xxxxxxxxxx]: https://github.com/ossrs/srs/issues/xxxxxxxxxx
[exo #828]: https://github.com/google/ExoPlayer/pull/828
diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp
index 8341e26d4..3e5a99c42 100644
--- a/trunk/src/app/srs_app_http_conn.cpp
+++ b/trunk/src/app/srs_app_http_conn.cpp
@@ -1310,6 +1310,19 @@ SrsResponseOnlyHttpConn::~SrsResponseOnlyHttpConn()
{
}
+int SrsResponseOnlyHttpConn::pop_message(ISrsHttpMessage** preq)
+{
+ int ret = ERROR_SUCCESS;
+
+ SrsStSocket skt(stfd);
+
+ if ((ret = parser->parse_message(&skt, this, preq)) != ERROR_SUCCESS) {
+ return ret;
+ }
+
+ return ret;
+}
+
int SrsResponseOnlyHttpConn::on_got_http_message(ISrsHttpMessage* msg)
{
int ret = ERROR_SUCCESS;
diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp
index 6e2532e1c..a3b4338ee 100644
--- a/trunk/src/app/srs_app_http_conn.hpp
+++ b/trunk/src/app/srs_app_http_conn.hpp
@@ -390,7 +390,7 @@ private:
class SrsHttpConn : public SrsConnection
{
-private:
+protected:
SrsHttpParser* parser;
ISrsHttpServeMux* http_mux;
public:
@@ -421,6 +421,13 @@ class SrsResponseOnlyHttpConn : public SrsHttpConn
public:
SrsResponseOnlyHttpConn(IConnectionManager* cm, st_netfd_t fd, ISrsHttpServeMux* m);
virtual ~SrsResponseOnlyHttpConn();
+public:
+ // Directly read a HTTP request message.
+ // It's exported for HTTP stream, such as HTTP FLV, only need to write to client when
+ // serving it, but we need to start a thread to read message to detect whether FD is closed.
+ // @see https://github.com/ossrs/srs/issues/636#issuecomment-298208427
+ // @remark Should only used in HTTP-FLV streaming connection.
+ virtual int pop_message(ISrsHttpMessage** preq);
public:
virtual int on_got_http_message(ISrsHttpMessage* msg);
};
diff --git a/trunk/src/app/srs_app_http_stream.cpp b/trunk/src/app/srs_app_http_stream.cpp
index 0272bcecd..f25852d09 100755
--- a/trunk/src/app/srs_app_http_stream.cpp
+++ b/trunk/src/app/srs_app_http_stream.cpp
@@ -54,6 +54,7 @@ using namespace std;
#include
#include
#include
+#include
#endif
@@ -535,10 +536,28 @@ int SrsLiveStream::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
#ifdef SRS_PERF_FAST_FLV_ENCODER
SrsFastFlvStreamEncoder* ffe = dynamic_cast(enc);
#endif
+
+ // Use receive thread to accept the close event to avoid FD leak.
+ // @see https://github.com/ossrs/srs/issues/636#issuecomment-298208427
+ SrsHttpMessage* hr = dynamic_cast(r);
+ SrsResponseOnlyHttpConn* hc = dynamic_cast(hr->connection());
+
+ SrsHttpRecvThread* trd = new SrsHttpRecvThread(hc);
+ SrsAutoFree(SrsHttpRecvThread, trd);
+
+ if ((ret = trd->start()) != ERROR_SUCCESS) {
+ srs_error("http: start notify thread failed, ret=%d", ret);
+ return ret;
+ }
// TODO: free and erase the disabled entry after all related connections is closed.
while (entry->enabled) {
pprint->elapse();
+
+ // Whether client closed the FD.
+ if ((ret = trd->error_code()) != ERROR_SUCCESS) {
+ return ret;
+ }
// get messages from consumer.
// each msg in msgs.msgs must be free, for the SrsMessageArray never free them.
diff --git a/trunk/src/app/srs_app_recv_thread.cpp b/trunk/src/app/srs_app_recv_thread.cpp
index a61f41f60..b8c8bcfdd 100644
--- a/trunk/src/app/srs_app_recv_thread.cpp
+++ b/trunk/src/app/srs_app_recv_thread.cpp
@@ -31,6 +31,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include
#include
#include
+#include
+#include
using namespace std;
@@ -523,3 +525,42 @@ void SrsPublishRecvThread::set_socket_buffer(int sleep_ms)
rtmp->set_recv_buffer(nb_rbuf);
}
+SrsHttpRecvThread::SrsHttpRecvThread(SrsResponseOnlyHttpConn* c)
+{
+ conn = c;
+ error = ERROR_SUCCESS;
+ trd = new SrsOneCycleThread("http-receive", this);
+}
+
+SrsHttpRecvThread::~SrsHttpRecvThread()
+{
+ srs_freep(trd);
+}
+
+int SrsHttpRecvThread::start()
+{
+ return trd->start();
+}
+
+int SrsHttpRecvThread::error_code()
+{
+ return error;
+}
+
+int SrsHttpRecvThread::cycle()
+{
+ int ret = ERROR_SUCCESS;
+
+ while (true) {
+ ISrsHttpMessage* req = NULL;
+ SrsAutoFree(ISrsHttpMessage, req);
+
+ if ((ret = conn->pop_message(&req)) != ERROR_SUCCESS) {
+ error = ret;
+ break;
+ }
+ }
+
+ return ret;
+}
+
diff --git a/trunk/src/app/srs_app_recv_thread.hpp b/trunk/src/app/srs_app_recv_thread.hpp
index a9b001b17..92f12dec1 100644
--- a/trunk/src/app/srs_app_recv_thread.hpp
+++ b/trunk/src/app/srs_app_recv_thread.hpp
@@ -43,6 +43,8 @@ class SrsRtmpConn;
class SrsSource;
class SrsRequest;
class SrsConsumer;
+class SrsHttpConn;
+class SrsResponseOnlyHttpConn;
/**
* for the recv thread to handle the message.
@@ -215,5 +217,29 @@ private:
virtual void set_socket_buffer(int sleep_ms);
};
+/**
+ * The HTTP receive thread, try to read messages util EOF.
+ * For example, the HTTP FLV serving thread will use the receive thread to break
+ * when client closed the request, to avoid FD leak.
+ * @see https://github.com/ossrs/srs/issues/636#issuecomment-298208427
+ */
+class SrsHttpRecvThread : public ISrsOneCycleThreadHandler
+{
+private:
+ SrsResponseOnlyHttpConn* conn;
+ SrsOneCycleThread* trd;
+ int error;
+public:
+ SrsHttpRecvThread(SrsResponseOnlyHttpConn* c);
+ virtual ~SrsHttpRecvThread();
+public:
+ virtual int start();
+public:
+ virtual int error_code();
+// interface ISrsOneCycleThreadHandler
+public:
+ virtual int cycle();
+};
+
#endif
diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp
index 765c01b7a..98c89c501 100644
--- a/trunk/src/core/srs_core.hpp
+++ b/trunk/src/core/srs_core.hpp
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
-#define VERSION_REVISION 240
+#define VERSION_REVISION 241
// generated by configure, only macros.
#include