mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
fix http reader bug, support infinite chunkted. 2.0.209
This commit is contained in:
parent
e2e6e76f92
commit
28080efec8
8 changed files with 160 additions and 23 deletions
|
@ -338,6 +338,7 @@ Remark:
|
|||
|
||||
## History
|
||||
|
||||
* v2.0, 2016-01-13, fix http reader bug, support infinite chunkted. 2.0.209
|
||||
* v2.0, 2016-01-09, merge [#559][pr #559] fix memory leak bug. 2.0.208
|
||||
* v2.0, 2016-01-09, merge [#558][pr #558] add tcUrl for on_publish.
|
||||
* v2.0, 2016-01-05, add keyword XCORE for coredump to identify the version. 2.0.207
|
||||
|
|
8
trunk/src/app/srs_app_http_api.cpp
Executable file → Normal file
8
trunk/src/app/srs_app_http_api.cpp
Executable file → Normal file
|
@ -950,8 +950,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<SrsHttpMessage*>(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()) {
|
||||
|
|
|
@ -55,6 +55,7 @@ using namespace std;
|
|||
#include <srs_app_http_static.hpp>
|
||||
#include <srs_app_http_stream.hpp>
|
||||
#include <srs_app_http_api.hpp>
|
||||
#include <srs_app_utility.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -347,15 +348,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)
|
||||
|
@ -480,8 +495,8 @@ 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;
|
||||
|
||||
// for not chunked
|
||||
if (!owner->is_chunked()) {
|
||||
// for not chunked and specified content length.
|
||||
if (!owner->is_chunked() && owner->content_length() != -1) {
|
||||
// when read completed, eof.
|
||||
if (nb_total_read >= (int)owner->content_length()) {
|
||||
is_eof = true;
|
||||
|
@ -495,6 +510,7 @@ SrsHttpMessage::SrsHttpMessage(SrsStSocket* io, SrsConnection* c) : ISrsHttpMess
|
|||
{
|
||||
conn = c;
|
||||
chunked = false;
|
||||
infinite_chunked = false;
|
||||
keep_alive = true;
|
||||
_uri = new SrsHttpUri();
|
||||
_body = new SrsHttpResponseReader(this, io);
|
||||
|
@ -532,11 +548,10 @@ int SrsHttpMessage::update(string url, http_parser* header, SrsFastBuffer* body,
|
|||
// parse uri from url.
|
||||
std::string host = get_request_header("Host");
|
||||
|
||||
// donot parse the empty host for uri,
|
||||
// for example, the response contains no host,
|
||||
// ignore it is ok.
|
||||
// use server public ip when no host specified.
|
||||
// to make telnet happy.
|
||||
if (host.empty()) {
|
||||
return ret;
|
||||
host= srs_get_public_internet_address();
|
||||
}
|
||||
|
||||
// parse uri to schema/server:port/path?query
|
||||
|
@ -674,6 +689,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();
|
||||
|
@ -728,6 +748,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;
|
||||
|
|
|
@ -156,9 +156,6 @@ typedef std::pair<std::string, std::string> 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:
|
||||
|
@ -183,6 +180,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.
|
||||
|
@ -235,6 +236,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.
|
||||
*/
|
||||
|
@ -255,6 +261,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.
|
||||
|
|
|
@ -485,7 +485,7 @@ void srs_update_proc_stat()
|
|||
static int user_hz = 0;
|
||||
if (user_hz <= 0) {
|
||||
user_hz = (int)sysconf(_SC_CLK_TCK);
|
||||
srs_trace("USER_HZ=%d", user_hz);
|
||||
srs_info("USER_HZ=%d", user_hz);
|
||||
srs_assert(user_hz > 0);
|
||||
}
|
||||
|
||||
|
@ -1279,6 +1279,66 @@ vector<string>& srs_get_local_ipv4_ips()
|
|||
return _srs_system_ipv4_ips;
|
||||
}
|
||||
|
||||
std::string _public_internet_address;
|
||||
|
||||
string srs_get_public_internet_address()
|
||||
{
|
||||
if (!_public_internet_address.empty()) {
|
||||
return _public_internet_address;
|
||||
}
|
||||
|
||||
std::vector<std::string>& ips = srs_get_local_ipv4_ips();
|
||||
|
||||
// find the best match public address.
|
||||
for (int i = 0; i < (int)ips.size(); i++) {
|
||||
std::string ip = ips[i];
|
||||
in_addr_t addr = inet_addr(ip.c_str());
|
||||
u_int32_t addr_h = ntohl(addr);
|
||||
// lo, 127.0.0.0-127.0.0.1
|
||||
if (addr_h >= 0x7f000000 && addr_h <= 0x7f000001) {
|
||||
srs_trace("ignore private address: %s", ip.c_str());
|
||||
continue;
|
||||
}
|
||||
// Class A 10.0.0.0-10.255.255.255
|
||||
if (addr_h >= 0x0a000000 && addr_h <= 0x0affffff) {
|
||||
srs_trace("ignore private address: %s", ip.c_str());
|
||||
continue;
|
||||
}
|
||||
// Class B 172.16.0.0-172.31.255.255
|
||||
if (addr_h >= 0xac100000 && addr_h <= 0xac1fffff) {
|
||||
srs_trace("ignore private address: %s", ip.c_str());
|
||||
continue;
|
||||
}
|
||||
// Class C 192.168.0.0-192.168.255.255
|
||||
if (addr_h >= 0xc0a80000 && addr_h <= 0xc0a8ffff) {
|
||||
srs_trace("ignore private address: %s", ip.c_str());
|
||||
continue;
|
||||
}
|
||||
srs_warn("use public address as ip: %s", ip.c_str());
|
||||
|
||||
_public_internet_address = ip;
|
||||
return ip;
|
||||
}
|
||||
|
||||
// no public address, use private address.
|
||||
for (int i = 0; i < (int)ips.size(); i++) {
|
||||
std::string ip = ips[i];
|
||||
in_addr_t addr = inet_addr(ip.c_str());
|
||||
u_int32_t addr_h = ntohl(addr);
|
||||
// lo, 127.0.0.0-127.0.0.1
|
||||
if (addr_h >= 0x7f000000 && addr_h <= 0x7f000001) {
|
||||
srs_trace("ignore private address: %s", ip.c_str());
|
||||
continue;
|
||||
}
|
||||
srs_warn("use private address as ip: %s", ip.c_str());
|
||||
|
||||
_public_internet_address = ip;
|
||||
return ip;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
string srs_get_local_ip(int fd)
|
||||
{
|
||||
std::string ip;
|
||||
|
|
|
@ -660,6 +660,9 @@ extern void srs_update_rtmp_server(int nb_conn, SrsKbps* kbps);
|
|||
// get local ip, fill to @param ips
|
||||
extern std::vector<std::string>& srs_get_local_ipv4_ips();
|
||||
|
||||
// get local public ip, empty string if no public internet address found.
|
||||
extern std::string srs_get_public_internet_address();
|
||||
|
||||
// get local or peer ip.
|
||||
// where local ip is the server ip which client connected.
|
||||
extern std::string srs_get_local_ip(int fd);
|
||||
|
|
|
@ -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 208
|
||||
#define VERSION_REVISION 209
|
||||
|
||||
// generated by configure, only macros.
|
||||
#include <srs_auto_headers.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<std::string, std::string> 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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue