1
0
Fork 0
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:
winlin 2016-01-13 12:44:51 +08:00
parent e2e6e76f92
commit 28080efec8
8 changed files with 160 additions and 23 deletions

View file

@ -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
View 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()) {

View file

@ -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;

View file

@ -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.

View file

@ -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;

View file

@ -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);

View file

@ -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>

View file

@ -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.