diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index fd18aa907..fa6188165 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1414,8 +1414,12 @@ int SrsHttpApi::process_request(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) { int ret = ERROR_SUCCESS; - srs_trace("HTTP %s %s, content-length=%"PRId64"", - r->method_str().c_str(), r->url().c_str(), r->content_length()); + SrsHttpMessage* hm = dynamic_cast(r); + srs_assert(hm); + + srs_trace("HTTP API %s %s, content-length=%"PRId64", chunked=%d/%d", + r->method_str().c_str(), r->url().c_str(), r->content_length(), + hm->is_chunked(), hm->is_infinite_chunked()); // method is OPTIONS and enable crossdomain, required crossdomain header. if (r->is_http_options() && _srs_config->get_http_api_crossdomain()) { diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index d23117c1a..fceb1d58a 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -357,15 +357,29 @@ int SrsHttpResponseReader::read(char* data, int nb_data, int* nb_read) } // read by specified content-length - int max = (int)owner->content_length() - (int)nb_total_read; - if (max <= 0) { - is_eof = true; - return ret; + if (owner->content_length() != -1) { + int max = (int)owner->content_length() - (int)nb_total_read; + if (max <= 0) { + is_eof = true; + return ret; + } + + // change the max to read. + nb_data = srs_min(nb_data, max); + return read_specified(data, nb_data, nb_read); } - // change the max to read. - nb_data = srs_min(nb_data, max); - return read_specified(data, nb_data, nb_read); + // infinite chunked mode, directly read. + if (owner->is_infinite_chunked()) { + srs_assert(!owner->is_chunked() && owner->content_length() == -1); + return read_specified(data, nb_data, nb_read); + } + + // infinite chunked mode, but user not set it, + // we think there is no data left. + is_eof = true; + + return ret; } int SrsHttpResponseReader::read_chunked(char* data, int nb_data, int* nb_read) @@ -505,6 +519,7 @@ SrsHttpMessage::SrsHttpMessage(ISrsProtocolReaderWriter* io, SrsConnection* c) : { conn = c; chunked = false; + infinite_chunked = false; keep_alive = true; _uri = new SrsHttpUri(); _body = new SrsHttpResponseReader(this, io); @@ -660,6 +675,11 @@ bool SrsHttpMessage::is_keep_alive() return keep_alive; } +bool SrsHttpMessage::is_infinite_chunked() +{ + return infinite_chunked; +} + string SrsHttpMessage::uri() { std::string uri = _uri->get_schema(); @@ -714,6 +734,25 @@ int SrsHttpMessage::parse_rest_id(string pattern) return -1; } +int SrsHttpMessage::enter_infinite_chunked() +{ + int ret = ERROR_SUCCESS; + + if (infinite_chunked) { + return ret; + } + + if (is_chunked() || content_length() != -1) { + ret = ERROR_HTTP_DATA_INVALID; + srs_error("infinite chunkted not supported in specified codec. ret=%d", ret); + return ret; + } + + infinite_chunked = true; + + return ret; +} + int SrsHttpMessage::body_read_all(string& body) { 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 30cfc3fe8..99b9b8211 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -152,9 +152,6 @@ typedef std::pair SrsHttpHeaderField; // 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 SrsHttpMessage : public ISrsHttpMessage { private: @@ -179,6 +176,10 @@ private: * whether the body is chunked. */ bool chunked; + /** + * whether the body is infinite chunked. + */ + bool infinite_chunked; /** * whether the request indicates should keep alive * for the http connection. @@ -231,6 +232,11 @@ public: * whether body is chunked encoding, for reader only. */ virtual bool is_chunked(); + /** + * whether body is infinite chunked encoding. + * @remark set by enter_infinite_chunked. + */ + virtual bool is_infinite_chunked(); /** * whether should keep the connection alive. */ @@ -251,6 +257,8 @@ public: * get the RESTful matched id. */ virtual int parse_rest_id(std::string pattern); +public: + virtual int enter_infinite_chunked(); public: /** * read body to string. diff --git a/trunk/src/protocol/srs_http_stack.hpp b/trunk/src/protocol/srs_http_stack.hpp index 98165da2b..63a26b254 100644 --- a/trunk/src/protocol/srs_http_stack.hpp +++ b/trunk/src/protocol/srs_http_stack.hpp @@ -231,6 +231,12 @@ public: * @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. + * @remark for some server, the content-length not specified and not chunked, + * which is actually the infinite chunked encoding, which after http header + * is http response data, it's ok for browser. that is, + * when user call this read, please ensure there is data to read(by content-length + * or by chunked), because the sdk never know whether there is no data or + * infinite chunked. */ virtual int read(char* data, int nb_data, int* nb_read) = 0; }; @@ -445,9 +451,19 @@ typedef std::pair SrsHttpHeaderField; // 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. - */ +// +// There are some modes to determine the length of body: +// 1. content-length and chunked. +// 2. user confirmed infinite chunked. +// 3. no body or user not confirmed infinite chunked. +// For example: +// ISrsHttpMessage* r = ...; +// while (!r->eof()) r->read(); // read in mode 1 or 3. +// For some server, we can confirm the body is infinite chunked: +// ISrsHttpMessage* r = ...; +// r->enter_infinite_chunked(); +// while (!r->eof()) r->read(); // read in mode 2 +// @rmark for mode 2, the infinite chunked, all left data is body. class ISrsHttpMessage { private: @@ -502,6 +518,12 @@ public: */ virtual int parse_rest_id(std::string pattern) = 0; public: + /** + * the left all data is chunked body, the infinite chunked mode, + * which is chunked encoding without chunked header. + * @remark error when message is in chunked or content-length specified. + */ + virtual int enter_infinite_chunked() = 0; /** * read body to string. * @remark for small http body.