mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Merge branch '3.0release' into develop
This commit is contained in:
commit
b8a81d8889
16 changed files with 374 additions and 121 deletions
14
AUTHORS.txt
14
AUTHORS.txt
|
@ -36,3 +36,17 @@ CONTRIBUTORS ordered by first contribution.
|
|||
* xubin<xubin@chnvideo.com>
|
||||
* intliang<yintiliang@gmail.com>
|
||||
* flowerwrong<sysuyangkang@gmail.com>
|
||||
* YLX<568414379@qq.com>
|
||||
* J<guotaojiang@qq.com>
|
||||
* Harlan<hailiang@gvrcraft.com>
|
||||
* hankun<hankun@bravovcloud.com>
|
||||
* JonathanBarratt<jonathan.barratt@gmail.com>
|
||||
* KeeganH<keeganwharris@gmail.com>
|
||||
* StevenLiu<lingjiujianke@gmail.com>
|
||||
* liuxc0116<liuxc0116@gmail.com>
|
||||
* ChengdongZhang<lmajzcd@sina.com>
|
||||
* lovacat<lovecat@china.sina.com>
|
||||
* qiang.li<qiang.li@verycdn.com.cn>
|
||||
* HungMingWu<u9089000@gmail.com>
|
||||
* Himer<xishizhaohua@qq.com>
|
||||
* xialixin<xlx0625@163.com>
|
|
@ -148,6 +148,7 @@ For previous versions, please read:
|
|||
|
||||
## V3 changes
|
||||
|
||||
* v3.0, 2019-12-24, For [#1508][bug #1508], support chunk length and content in multiple parts.
|
||||
* v3.0, 2019-12-23, Merge SRS2 for running srs-librtmp on Windows. 3.0.80
|
||||
* v3.0, 2019-12-23, For [#1535][bug #1535], deprecate Adobe FMS/AMS edge token traversing([CN][v3_CN_DRM2], [EN][v3_EN_DRM2]) authentication. 3.0.79
|
||||
* v3.0, 2019-12-23, For [#1535][bug #1535], deprecate BWT(bandwidth testing)([CN][v1_CN_BandwidthTestTool], [EN][v1_EN_BandwidthTestTool]). 3.0.78
|
||||
|
|
18
trunk/scripts/new_authors.sh
Executable file
18
trunk/scripts/new_authors.sh
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
|
||||
AFILE=`dirname $0`/../../AUTHORS.txt
|
||||
if [[ ! -f $AFILE ]]; then echo "No file at $AFILE"; exit -1; fi
|
||||
|
||||
authors=`git log --format='%ae'|grep -v localhost|grep -v demo|grep -v none|sort|uniq`
|
||||
if [[ $? -ne 0 ]]; then echo "no authors"; exit -1; fi
|
||||
|
||||
for author in $authors; do
|
||||
echo $author| grep 'winlin' >/dev/null 2>&1 && continue;
|
||||
echo $author| grep 'winterserver' >/dev/null 2>&1 && continue;
|
||||
echo $author| grep 'wenjie.zhao' >/dev/null 2>&1 && continue;
|
||||
echo $author| grep 'zhaowenjie' >/dev/null 2>&1 && continue;
|
||||
|
||||
grep $author $AFILE 1>/dev/null 2>/dev/null && continue;
|
||||
|
||||
git log -1 --author="$author" --format='%an<%ae>'| sed 's/ //g'
|
||||
done
|
|
@ -295,7 +295,7 @@ srs_error_t SrsHttpFileReader::read(void* buf, size_t count, ssize_t* pnread)
|
|||
|
||||
int total_read = 0;
|
||||
while (total_read < (int)count) {
|
||||
int nread = 0;
|
||||
ssize_t nread = 0;
|
||||
if ((err = http->read((char*)buf + total_read, (int)(count - total_read), &nread)) != srs_success) {
|
||||
return srs_error_wrap(err, "read");
|
||||
}
|
||||
|
@ -306,7 +306,7 @@ srs_error_t SrsHttpFileReader::read(void* buf, size_t count, ssize_t* pnread)
|
|||
}
|
||||
|
||||
srs_assert(nread);
|
||||
total_read += nread;
|
||||
total_read += (int)nread;
|
||||
}
|
||||
|
||||
if (pnread) {
|
||||
|
|
|
@ -3855,17 +3855,6 @@ srs_error_t SrsConfig::check_normal_config()
|
|||
SRS_CONSTS_RTMP_MIN_CHUNK_SIZE, SRS_CONSTS_RTMP_MAX_CHUNK_SIZE);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < (int)vhosts.size(); i++) {
|
||||
SrsConfDirective* vhost = vhosts[i];
|
||||
srs_assert(vhost != NULL);
|
||||
if (get_dvr_enabled(vhost->arg0())) {
|
||||
srs_warn("can't enable vhost.dvr of %s", vhost->arg0().c_str());
|
||||
}
|
||||
if (get_hls_enabled(vhost->arg0())) {
|
||||
srs_warn("can't enable vhost.hls of %s", vhost->arg0().c_str());
|
||||
}
|
||||
// TODO: FIXME: required http server when hls storage is ram or both.
|
||||
}
|
||||
|
||||
// asprocess conflict with daemon
|
||||
if (get_asprocess() && get_daemon()) {
|
||||
|
|
|
@ -398,11 +398,11 @@ srs_error_t SrsHttpHooks::on_hls_notify(int cid, std::string url, SrsRequest* re
|
|||
int nb_read = 0;
|
||||
ISrsHttpResponseReader* br = msg->body_reader();
|
||||
while (nb_read < nb_notify && !br->eof()) {
|
||||
int nb_bytes = 0;
|
||||
ssize_t nb_bytes = 0;
|
||||
if ((err = br->read(buf, nb_buf, &nb_bytes)) != srs_success) {
|
||||
break;
|
||||
}
|
||||
nb_read += nb_bytes;
|
||||
nb_read += (int)nb_bytes;
|
||||
}
|
||||
|
||||
int spenttime = (int)(srsu2ms(srs_update_system_time()) - starttime);
|
||||
|
|
|
@ -694,6 +694,7 @@ srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp)
|
|||
nb_raw = stream->size() - stream->pos();
|
||||
|
||||
if (avc_packet_type == SrsVideoAvcFrameTraitSequenceHeader) {
|
||||
// TODO: FIXME: Maybe we should ignore any error for parsing sps/pps.
|
||||
if ((err = avc_demux_sps_pps(stream)) != srs_success) {
|
||||
return srs_error_wrap(err, "demux SPS/PPS");
|
||||
}
|
||||
|
@ -708,6 +709,9 @@ srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp)
|
|||
return err;
|
||||
}
|
||||
|
||||
// For media server, we don't care the codec, so we just try to parse sps-pps, and we could ignore any error if fail.
|
||||
// LCOV_EXCL_START
|
||||
|
||||
srs_error_t SrsFormat::avc_demux_sps_pps(SrsBuffer* stream)
|
||||
{
|
||||
// AVCDecoderConfigurationRecord
|
||||
|
@ -1016,6 +1020,8 @@ srs_error_t SrsFormat::avc_demux_sps_rbsp(char* rbsp, int nb_rbsp)
|
|||
return err;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
srs_error_t SrsFormat::video_nalu_demux(SrsBuffer* stream)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
|
|
@ -866,6 +866,7 @@ public:
|
|||
|
||||
// 8.6.6 Edit List Box
|
||||
// ISO_IEC_14496-12-base-format-2012.pdf, page 55
|
||||
// LCOV_EXCL_START
|
||||
class SrsMp4ElstEntry
|
||||
{
|
||||
public:
|
||||
|
@ -890,6 +891,7 @@ public:
|
|||
virtual std::stringstream& dumps(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
};
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
// 8.6.6 Edit List Box (elst)
|
||||
// ISO_IEC_14496-12-base-format-2012.pdf, page 54
|
||||
|
@ -1564,6 +1566,7 @@ public:
|
|||
|
||||
// 8.6.1.3 Composition Time to Sample Box (ctts), for Video.
|
||||
// ISO_IEC_14496-12-base-format-2012.pdf, page 49
|
||||
// LCOV_EXCL_START
|
||||
class SrsMp4CttsEntry
|
||||
{
|
||||
public:
|
||||
|
@ -1580,6 +1583,7 @@ public:
|
|||
public:
|
||||
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
};
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
// 8.6.1.3 Composition Time to Sample Box (ctts), for Video.
|
||||
// ISO_IEC_14496-12-base-format-2012.pdf, page 49
|
||||
|
|
|
@ -810,6 +810,8 @@ SrsTsPacket* SrsTsPacket::create_pes_first(SrsTsContext* context,
|
|||
pkt->payload = pes;
|
||||
|
||||
if (pcr >= 0) {
|
||||
// Ignore coverage for PCR, we don't use it in HLS.
|
||||
// LCOV_EXCL_START
|
||||
SrsTsAdaptationField* af = new SrsTsAdaptationField(pkt);
|
||||
pkt->adaptation_field = af;
|
||||
pkt->adaption_field_control = SrsTsAdaptationFieldTypeBoth;
|
||||
|
@ -825,6 +827,7 @@ SrsTsPacket* SrsTsPacket::create_pes_first(SrsTsContext* context,
|
|||
af->adaptation_field_extension_flag = 0;
|
||||
af->program_clock_reference_base = pcr;
|
||||
af->program_clock_reference_extension = 0;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
pes->packet_start_code_prefix = 0x01;
|
||||
|
@ -973,6 +976,8 @@ srs_error_t SrsTsAdaptationField::decode(SrsBuffer* stream)
|
|||
program_clock_reference_base = (pcrv >> 15) & 0x1ffffffffLL;
|
||||
}
|
||||
|
||||
// Ignore coverage for bellow, we don't use it in HLS.
|
||||
// LCOV_EXCL_START
|
||||
if (OPCR_flag) {
|
||||
if (!stream->require(6)) {
|
||||
return srs_error_new(ERROR_STREAM_CASTER_TS_AF, "ts: demux af OPCR_flag");
|
||||
|
@ -1080,6 +1085,7 @@ srs_error_t SrsTsAdaptationField::decode(SrsBuffer* stream)
|
|||
nb_af_ext_reserved = adaptation_field_extension_length - (stream->pos() - pos_af_ext);
|
||||
stream->skip(nb_af_ext_reserved);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
nb_af_reserved = adaption_field_length - (stream->pos() - pos_af);
|
||||
stream->skip(nb_af_reserved);
|
||||
|
@ -1144,6 +1150,8 @@ srs_error_t SrsTsAdaptationField::encode(SrsBuffer* stream)
|
|||
tmpv |= (transport_private_data_flag << 1) & 0x02;
|
||||
stream->write_1bytes(tmpv);
|
||||
|
||||
// Ignore the coverage bellow, for we don't use them in HLS.
|
||||
// LCOV_EXCL_START
|
||||
if (PCR_flag) {
|
||||
if (!stream->require(6)) {
|
||||
return srs_error_new(ERROR_STREAM_CASTER_TS_AF, "ts: mux af PCR_flag");
|
||||
|
@ -1236,6 +1244,7 @@ srs_error_t SrsTsAdaptationField::encode(SrsBuffer* stream)
|
|||
stream->skip(nb_af_ext_reserved);
|
||||
}
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
if (nb_af_reserved) {
|
||||
stream->skip(nb_af_reserved);
|
||||
|
@ -1461,6 +1470,9 @@ srs_error_t SrsTsPayloadPES::decode(SrsBuffer* stream, SrsTsMessage** ppmsg)
|
|||
msg->pts = pts;
|
||||
}
|
||||
|
||||
// Ignore coverage bellow, for we don't use them in HLS.
|
||||
// LCOV_EXCL_START
|
||||
|
||||
// 6B
|
||||
if (ESCR_flag) {
|
||||
ESCR_extension = 0;
|
||||
|
@ -1589,6 +1601,8 @@ srs_error_t SrsTsPayloadPES::decode(SrsBuffer* stream, SrsTsMessage** ppmsg)
|
|||
stream->skip(nb_stuffings);
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
// PES_packet_data_byte, page58.
|
||||
// the packet size contains the header size.
|
||||
// The number of PES_packet_data_bytes, N, is specified by the
|
||||
|
@ -1610,6 +1624,9 @@ srs_error_t SrsTsPayloadPES::decode(SrsBuffer* stream, SrsTsMessage** ppmsg)
|
|||
if ((err = msg->dump(stream, &nb_bytes)) != srs_success) {
|
||||
return srs_error_wrap(err, "dump pes");
|
||||
}
|
||||
|
||||
// Ignore coverage bellow, for we don't use them in HLS.
|
||||
// LCOV_EXCL_START
|
||||
} else if (sid == SrsTsPESStreamIdProgramStreamMap
|
||||
|| sid == SrsTsPESStreamIdPrivateStream2
|
||||
|| sid == SrsTsPESStreamIdEcmStream
|
||||
|
@ -1633,6 +1650,8 @@ srs_error_t SrsTsPayloadPES::decode(SrsBuffer* stream, SrsTsMessage** ppmsg)
|
|||
nb_paddings = stream->size() - stream->pos();
|
||||
stream->skip(nb_paddings);
|
||||
srs_info("ts: drop %dB padding bytes", nb_paddings);
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
} else {
|
||||
int nb_drop = stream->size() - stream->pos();
|
||||
stream->skip(nb_drop);
|
||||
|
@ -1687,11 +1706,14 @@ int SrsTsPayloadPES::size()
|
|||
sz += PES_extension_flag? 1:0;
|
||||
|
||||
if (PES_extension_flag) {
|
||||
// Ignore coverage bellow, for we don't use them in HLS.
|
||||
// LCOV_EXCL_START
|
||||
sz += PES_private_data_flag? 16:0;
|
||||
sz += pack_header_field_flag ? 1 + pack_field.size() : 0; // 1+x bytes.
|
||||
sz += program_packet_sequence_counter_flag? 2:0;
|
||||
sz += P_STD_buffer_flag? 2:0;
|
||||
sz += PES_extension_flag_2 ? 1 + PES_extension_field.size() : 0; // 1+x bytes.
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
PES_header_data_length = sz - PES_header_data_length;
|
||||
|
||||
|
@ -1803,6 +1825,9 @@ srs_error_t SrsTsPayloadPES::encode(SrsBuffer* stream)
|
|||
}
|
||||
}
|
||||
|
||||
// Ignore coverage bellow, for we don't use them in HLS.
|
||||
// LCOV_EXCL_START
|
||||
|
||||
// 6B
|
||||
if (ESCR_flag) {
|
||||
stream->skip(6);
|
||||
|
@ -1862,6 +1887,8 @@ srs_error_t SrsTsPayloadPES::encode(SrsBuffer* stream)
|
|||
srs_warn("ts: demux PES, ignore the stuffings.");
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -568,11 +568,11 @@ int srs_do_create_dir_recursively(string dir)
|
|||
|
||||
// create curren dir.
|
||||
// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213
|
||||
#ifndef _WIN32
|
||||
#ifdef _WIN32
|
||||
if (::_mkdir(dir.c_str()) < 0) {
|
||||
#else
|
||||
mode_t mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH;
|
||||
if (::mkdir(dir.c_str(), mode) < 0) {
|
||||
#else
|
||||
if (::_mkdir(dir.c_str()) < 0) {
|
||||
#endif
|
||||
if (errno == EEXIST) {
|
||||
return ERROR_SYSTEM_DIR_EXISTS;
|
||||
|
|
|
@ -187,7 +187,7 @@ int srs_hijack_io_set_recv_timeout(srs_hijack_io_t ctx, int64_t tm)
|
|||
SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD tv = (DWORD)(timeout_us/1000);
|
||||
DWORD tv = (DWORD)(tm);
|
||||
|
||||
// To convert tv to const char* to make VS2015 happy.
|
||||
if (setsockopt(skt->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
|
||||
|
@ -229,7 +229,7 @@ int srs_hijack_io_set_send_timeout(srs_hijack_io_t ctx, int64_t tm)
|
|||
SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD tv = (DWORD)(timeout_us/1000);
|
||||
DWORD tv = (DWORD)(tm);
|
||||
|
||||
// To convert tv to const char* to make VS2015 happy.
|
||||
if (setsockopt(skt->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#include <srs_kernel_io.hpp>
|
||||
|
||||
// Default http listen port.
|
||||
#define SRS_DEFAULT_HTTP_PORT 80
|
||||
|
||||
|
@ -160,7 +162,7 @@ public:
|
|||
// w->header()->set_content_type("text/plain; charset=utf-8");
|
||||
// w->header()->set_content_length(msg.length());
|
||||
// w->write_header(SRS_CONSTS_HTTP_OK);
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->write((char*)msg.data(), (int)msg.length()); // write N times, N>0
|
||||
// w->final_request(); // optional flush.
|
||||
// Usage 2, response with HTTP code only, zero content length.
|
||||
// ISrsHttpResponseWriter* w; // create or get response.
|
||||
|
@ -215,7 +217,7 @@ public:
|
|||
};
|
||||
|
||||
// The reader interface for http response.
|
||||
class ISrsHttpResponseReader
|
||||
class ISrsHttpResponseReader : public ISrsReader
|
||||
{
|
||||
public:
|
||||
ISrsHttpResponseReader();
|
||||
|
@ -223,18 +225,6 @@ public:
|
|||
public:
|
||||
// Whether response read EOF.
|
||||
virtual bool eof() = 0;
|
||||
// Read from the response body.
|
||||
// @param data, the buffer to read data buffer to.
|
||||
// @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 srs_error_t read(char* data, int nb_data, int* nb_read) = 0;
|
||||
};
|
||||
|
||||
// Objects implementing the Handler interface can be
|
||||
|
|
|
@ -185,6 +185,10 @@ int SrsHttpParser::on_headers_complete(http_parser* parser)
|
|||
// save the parser when header parse completed.
|
||||
obj->state = SrsHttpParseStateHeaderComplete;
|
||||
|
||||
// We must update the body start when header complete, because sometimes we only got header.
|
||||
// When we got the body start event, we will update it to much precious position.
|
||||
obj->p_body_start = obj->buffer->bytes() + obj->buffer->size();
|
||||
|
||||
srs_info("***HEADERS COMPLETE***");
|
||||
|
||||
// see http_parser.c:1570, return 1 to skip body.
|
||||
|
@ -551,7 +555,7 @@ srs_error_t SrsHttpMessage::body_read_all(string& body)
|
|||
|
||||
// whatever, read util EOF.
|
||||
while (!_body->eof()) {
|
||||
int nb_read = 0;
|
||||
ssize_t nb_read = 0;
|
||||
if ((err = _body->read(buf, SRS_HTTP_READ_CACHE_BYTES, &nb_read)) != srs_success) {
|
||||
return srs_error_wrap(err, "read body");
|
||||
}
|
||||
|
@ -699,7 +703,9 @@ srs_error_t SrsHttpResponseWriter::write(char* data, int size)
|
|||
if (hdr->content_type().empty()) {
|
||||
hdr->set_content_type("text/plain; charset=utf-8");
|
||||
}
|
||||
if (hdr->content_length() == -1) {
|
||||
hdr->set_content_length(size);
|
||||
}
|
||||
write_header(SRS_CONSTS_HTTP_OK);
|
||||
}
|
||||
|
||||
|
@ -912,7 +918,7 @@ bool SrsHttpResponseReader::eof()
|
|||
return is_eof;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpResponseReader::read(char* data, int nb_data, int* nb_read)
|
||||
srs_error_t SrsHttpResponseReader::read(void* data, size_t nb_data, ssize_t* nb_read)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
|
@ -927,7 +933,7 @@ srs_error_t SrsHttpResponseReader::read(char* data, int nb_data, int* nb_read)
|
|||
|
||||
// read by specified content-length
|
||||
if (owner->content_length() != -1) {
|
||||
int max = (int)owner->content_length() - (int)nb_total_read;
|
||||
size_t max = (size_t)owner->content_length() - (size_t)nb_total_read;
|
||||
if (max <= 0) {
|
||||
is_eof = true;
|
||||
return err;
|
||||
|
@ -951,7 +957,7 @@ srs_error_t SrsHttpResponseReader::read(char* data, int nb_data, int* nb_read)
|
|||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpResponseReader::read_chunked(char* data, int nb_data, int* nb_read)
|
||||
srs_error_t SrsHttpResponseReader::read_chunked(void* data, size_t nb_data, ssize_t* nb_read)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
|
@ -1003,19 +1009,20 @@ srs_error_t SrsHttpResponseReader::read_chunked(char* data, int nb_data, int* nb
|
|||
}
|
||||
|
||||
// all bytes in chunk is left now.
|
||||
nb_chunk = nb_left_chunk = ilength;
|
||||
nb_chunk = nb_left_chunk = (size_t)ilength;
|
||||
}
|
||||
|
||||
if (nb_chunk <= 0) {
|
||||
// for the last chunk, eof.
|
||||
is_eof = true;
|
||||
*nb_read = 0;
|
||||
} 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);
|
||||
err = read_specified(data, nb_bytes, &nb_bytes);
|
||||
size_t nb_bytes = srs_min(nb_left_chunk, nb_data);
|
||||
err = read_specified(data, nb_bytes, (ssize_t*)&nb_bytes);
|
||||
|
||||
// the nb_bytes used for output already read size of bytes.
|
||||
if (nb_read) {
|
||||
|
@ -1023,12 +1030,13 @@ srs_error_t SrsHttpResponseReader::read_chunked(char* data, int nb_data, int* nb
|
|||
}
|
||||
nb_left_chunk -= nb_bytes;
|
||||
|
||||
// error or still left bytes in chunk, ignore and read in future.
|
||||
if (err != srs_success) {
|
||||
return srs_error_wrap(err, "read specified");
|
||||
}
|
||||
|
||||
// If still left bytes in chunk, ignore and read in future.
|
||||
if (nb_left_chunk > 0) {
|
||||
return srs_error_new(ERROR_HTTP_INVALID_CHUNK_HEADER, "read specified left=%d", nb_left_chunk);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1041,7 +1049,7 @@ srs_error_t SrsHttpResponseReader::read_chunked(char* data, int nb_data, int* nb
|
|||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpResponseReader::read_specified(char* data, int nb_data, int* nb_read)
|
||||
srs_error_t SrsHttpResponseReader::read_specified(void* data, size_t nb_data, ssize_t* nb_read)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
|
@ -1052,7 +1060,7 @@ srs_error_t SrsHttpResponseReader::read_specified(char* data, int nb_data, int*
|
|||
}
|
||||
}
|
||||
|
||||
int nb_bytes = srs_min(nb_data, buffer->size());
|
||||
size_t nb_bytes = srs_min(nb_data, (size_t)buffer->size());
|
||||
|
||||
// read data to buffer.
|
||||
srs_assert(nb_bytes);
|
||||
|
|
|
@ -261,9 +261,9 @@ private:
|
|||
SrsFastStream* buffer;
|
||||
bool is_eof;
|
||||
// The left bytes in chunk.
|
||||
int nb_left_chunk;
|
||||
size_t nb_left_chunk;
|
||||
// The number of bytes of current chunk.
|
||||
int nb_chunk;
|
||||
size_t nb_chunk;
|
||||
// Already read total bytes.
|
||||
int64_t nb_total_read;
|
||||
public:
|
||||
|
@ -274,10 +274,10 @@ public:
|
|||
// Interface ISrsHttpResponseReader
|
||||
public:
|
||||
virtual bool eof();
|
||||
virtual srs_error_t read(char* data, int nb_data, int* nb_read);
|
||||
virtual srs_error_t read(void* buf, size_t size, ssize_t* nread);
|
||||
private:
|
||||
virtual srs_error_t read_chunked(char* data, int nb_data, int* nb_read);
|
||||
virtual srs_error_t read_specified(char* data, int nb_data, int* nb_read);
|
||||
virtual srs_error_t read_chunked(void* buf, size_t size, ssize_t* nread);
|
||||
virtual srs_error_t read_specified(void* buf, size_t size, ssize_t* nread);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,6 +34,60 @@ using namespace std;
|
|||
#include <srs_utest_kernel.hpp>
|
||||
#include <srs_app_http_static.hpp>
|
||||
|
||||
class MockMSegmentsReader : public ISrsReader
|
||||
{
|
||||
public:
|
||||
vector<string> in_bytes;
|
||||
public:
|
||||
MockMSegmentsReader();
|
||||
virtual ~MockMSegmentsReader();
|
||||
public:
|
||||
virtual void append(string b) {
|
||||
in_bytes.push_back(b);
|
||||
}
|
||||
virtual srs_error_t read(void* buf, size_t size, ssize_t* nread);
|
||||
};
|
||||
|
||||
MockMSegmentsReader::MockMSegmentsReader()
|
||||
{
|
||||
}
|
||||
|
||||
MockMSegmentsReader::~MockMSegmentsReader()
|
||||
{
|
||||
}
|
||||
|
||||
srs_error_t MockMSegmentsReader::read(void* buf, size_t size, ssize_t* nread)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
for (;;) {
|
||||
if (in_bytes.empty() || size <= 0) {
|
||||
return srs_error_new(-1, "EOF");
|
||||
}
|
||||
|
||||
string v = in_bytes[0];
|
||||
if (v.empty()) {
|
||||
in_bytes.erase(in_bytes.begin());
|
||||
continue;
|
||||
}
|
||||
|
||||
int nn = srs_min(size, v.length());
|
||||
memcpy(buf, v.data(), nn);
|
||||
if (nread) {
|
||||
*nread = nn;
|
||||
}
|
||||
|
||||
if (nn < (int)v.length()) {
|
||||
in_bytes[0] = string(v.data() + nn, v.length() - nn);
|
||||
} else {
|
||||
in_bytes.erase(in_bytes.begin());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
class MockResponseWriter : virtual public ISrsHttpResponseWriter, virtual public ISrsHttpHeaderFilter
|
||||
{
|
||||
public:
|
||||
|
@ -192,12 +246,41 @@ VOID TEST(ProtocolHTTPTest, ResponseDetect)
|
|||
|
||||
VOID TEST(ProtocolHTTPTest, ResponseWriter)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
// Directly final_request, should work.
|
||||
if (true) {
|
||||
MockResponseWriter w;
|
||||
w.header()->set_content_length(0);
|
||||
HELPER_ASSERT_SUCCESS(w.final_request());
|
||||
}
|
||||
|
||||
// Directly final_request, should work.
|
||||
if (true) {
|
||||
MockResponseWriter w;
|
||||
HELPER_ASSERT_SUCCESS(w.final_request());
|
||||
}
|
||||
|
||||
// When content-length is set, we could write multiple parts.
|
||||
if (true) {
|
||||
MockResponseWriter w;
|
||||
|
||||
char msg[] = "Hello, world!";
|
||||
w.header()->set_content_length(sizeof(msg) - 1);
|
||||
HELPER_EXPECT_SUCCESS(w.write((char*)msg, 5));
|
||||
HELPER_EXPECT_SUCCESS(w.write((char*)(msg+5), 2));
|
||||
HELPER_EXPECT_SUCCESS(w.write((char*)(msg+7), 5));
|
||||
HELPER_EXPECT_SUCCESS(w.write((char*)(msg+12), 1));
|
||||
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
|
||||
}
|
||||
|
||||
// If directly write string, response with content-length.
|
||||
if (true) {
|
||||
MockResponseWriter w;
|
||||
|
||||
char msg[] = "Hello, world!";
|
||||
w.write((char*)msg, sizeof(msg) - 1);
|
||||
HELPER_EXPECT_SUCCESS(w.write((char*)msg, sizeof(msg) - 1));
|
||||
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
|
||||
}
|
||||
|
@ -211,8 +294,8 @@ VOID TEST(ProtocolHTTPTest, ResponseWriter)
|
|||
w.header()->set_content_type("text/plain; charset=utf-8");
|
||||
w.header()->set_content_length(sizeof(msg) - 1);
|
||||
w.write_header(SRS_CONSTS_HTTP_OK);
|
||||
w.write((char*)msg, sizeof(msg) - 1);
|
||||
w.final_request();
|
||||
HELPER_EXPECT_SUCCESS(w.write((char*)msg, sizeof(msg) - 1));
|
||||
HELPER_ASSERT_SUCCESS(w.final_request());
|
||||
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
|
||||
}
|
||||
|
@ -223,7 +306,7 @@ VOID TEST(ProtocolHTTPTest, ResponseWriter)
|
|||
|
||||
w.header()->set_content_length(0);
|
||||
w.write_header(SRS_CONSTS_HTTP_OK);
|
||||
w.final_request();
|
||||
HELPER_ASSERT_SUCCESS(w.final_request());
|
||||
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "", w);
|
||||
}
|
||||
|
@ -234,7 +317,7 @@ VOID TEST(ProtocolHTTPTest, ResponseWriter)
|
|||
|
||||
w.header()->set_content_length(0);
|
||||
w.write_header(SRS_CONSTS_HTTP_OK);
|
||||
w.write(NULL, 0);
|
||||
HELPER_EXPECT_SUCCESS(w.write(NULL, 0));
|
||||
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "", w);
|
||||
}
|
||||
|
@ -245,9 +328,9 @@ VOID TEST(ProtocolHTTPTest, ResponseWriter)
|
|||
|
||||
w.header()->set_content_type("application/octet-stream");
|
||||
w.write_header(SRS_CONSTS_HTTP_OK);
|
||||
w.write((char*)"Hello", 5);
|
||||
w.write((char*)", world!", 8);
|
||||
w.final_request();
|
||||
HELPER_EXPECT_SUCCESS(w.write((char*)"Hello", 5));
|
||||
HELPER_EXPECT_SUCCESS(w.write((char*)", world!", 8));
|
||||
HELPER_ASSERT_SUCCESS(w.final_request());
|
||||
|
||||
__MOCK_HTTP_EXPECT_STREQ2(200, "5\r\nHello\r\n8\r\n, world!\r\n0\r\n\r\n", w);
|
||||
}
|
||||
|
@ -256,8 +339,8 @@ VOID TEST(ProtocolHTTPTest, ResponseWriter)
|
|||
|
||||
w.header()->set_content_type("application/octet-stream");
|
||||
w.write_header(SRS_CONSTS_HTTP_OK);
|
||||
w.write((char*)"Hello, world!", 13);
|
||||
w.final_request();
|
||||
HELPER_EXPECT_SUCCESS(w.write((char*)"Hello, world!", 13));
|
||||
HELPER_ASSERT_SUCCESS(w.final_request());
|
||||
|
||||
__MOCK_HTTP_EXPECT_STREQ2(200, "d\r\nHello, world!\r\n0\r\n\r\n", w);
|
||||
}
|
||||
|
@ -266,8 +349,8 @@ VOID TEST(ProtocolHTTPTest, ResponseWriter)
|
|||
|
||||
w.header()->set_content_type("application/octet-stream");
|
||||
w.write_header(SRS_CONSTS_HTTP_OK);
|
||||
w.write((char*)"Hello, world!", 13);
|
||||
w.final_request();
|
||||
HELPER_EXPECT_SUCCESS(w.write((char*)"Hello, world!", 13));
|
||||
HELPER_ASSERT_SUCCESS(w.final_request());
|
||||
|
||||
__MOCK_HTTP_EXPECT_STREQ2(200, "d\r\nHello, world!\r\n0\r\n\r\n", w);
|
||||
}
|
||||
|
@ -275,18 +358,176 @@ VOID TEST(ProtocolHTTPTest, ResponseWriter)
|
|||
// If directly write empty string, sent an empty response with content-length 0
|
||||
if (true) {
|
||||
MockResponseWriter w;
|
||||
w.write(NULL, 0);
|
||||
HELPER_EXPECT_SUCCESS(w.write(NULL, 0));
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "", w);
|
||||
}
|
||||
|
||||
// If directly final request, response with EOF of chunked.
|
||||
if (true) {
|
||||
MockResponseWriter w;
|
||||
w.final_request();
|
||||
HELPER_ASSERT_SUCCESS(w.final_request());
|
||||
__MOCK_HTTP_EXPECT_STREQ2(200, "0\r\n\r\n", w);
|
||||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtocolHTTPTest, ChunkSmallBuffer)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
// No chunk end flag, error.
|
||||
if (true) {
|
||||
MockMSegmentsReader io;
|
||||
io.append(mock_http_response2(200, "0d\r\n"));
|
||||
io.append("Hello, world!\r\n");
|
||||
|
||||
SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false));
|
||||
ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg));
|
||||
|
||||
char buf[32]; ssize_t nread = 0;
|
||||
ISrsHttpResponseReader* r = msg->body_reader();
|
||||
|
||||
HELPER_ARRAY_INIT(buf, sizeof(buf), 0);
|
||||
HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread));
|
||||
EXPECT_EQ(13, nread);
|
||||
EXPECT_STREQ("Hello, world!", buf);
|
||||
|
||||
err = r->read(buf, 32, &nread);
|
||||
EXPECT_EQ(-1, srs_error_code(err));
|
||||
srs_freep(err);
|
||||
|
||||
srs_freep(msg);
|
||||
}
|
||||
|
||||
// Read util EOF(nread=0) or err(ERROR_HTTP_RESPONSE_EOF).
|
||||
if (true) {
|
||||
MockMSegmentsReader io;
|
||||
io.append(mock_http_response2(200, "0d\r\n"));
|
||||
io.append("Hello, world!\r\n0\r\n\r\n");
|
||||
|
||||
SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false));
|
||||
ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg));
|
||||
|
||||
char buf[32]; ssize_t nread = 0;
|
||||
ISrsHttpResponseReader* r = msg->body_reader();
|
||||
|
||||
HELPER_ARRAY_INIT(buf, sizeof(buf), 0);
|
||||
HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread));
|
||||
EXPECT_EQ(13, nread);
|
||||
EXPECT_STREQ("Hello, world!", buf);
|
||||
|
||||
HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread));
|
||||
EXPECT_EQ(0, nread);
|
||||
|
||||
err = r->read(buf, 32, &nread);
|
||||
EXPECT_EQ(ERROR_HTTP_RESPONSE_EOF, srs_error_code(err));
|
||||
srs_freep(err);
|
||||
|
||||
srs_freep(msg);
|
||||
}
|
||||
|
||||
// In this case, we only got header complete, no body start event.
|
||||
if (true) {
|
||||
MockMSegmentsReader io;
|
||||
io.append(mock_http_response2(200, "0d\r\n"));
|
||||
io.append("Hello, world!\r\n0\r\n\r\n");
|
||||
|
||||
SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false));
|
||||
ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg));
|
||||
|
||||
char buf[32]; ssize_t nread = 0;
|
||||
ISrsHttpResponseReader* r = msg->body_reader();
|
||||
|
||||
HELPER_ARRAY_INIT(buf, sizeof(buf), 0);
|
||||
HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread));
|
||||
EXPECT_EQ(13, nread);
|
||||
EXPECT_STREQ("Hello, world!", buf);
|
||||
|
||||
srs_freep(msg);
|
||||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtocolHTTPTest, ClientSmallBuffer)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
// The chunk content is sent in multiple parts.
|
||||
if (true) {
|
||||
MockMSegmentsReader io;
|
||||
io.append(mock_http_response2(200, "0d\r\n"));
|
||||
io.append("Hello,");
|
||||
io.append(" world!");
|
||||
io.append("\r\n0\r\n\r\n");
|
||||
|
||||
SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false));
|
||||
ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg));
|
||||
|
||||
char buf[32]; ssize_t nread = 0;
|
||||
ISrsHttpResponseReader* r = msg->body_reader();
|
||||
|
||||
HELPER_ARRAY_INIT(buf, sizeof(buf), 0);
|
||||
HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread));
|
||||
EXPECT_EQ(6, nread);
|
||||
EXPECT_STREQ("Hello,", buf);
|
||||
|
||||
HELPER_ARRAY_INIT(buf, sizeof(buf), 0);
|
||||
HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread));
|
||||
EXPECT_EQ(7, nread);
|
||||
EXPECT_STREQ(" world!", buf);
|
||||
|
||||
srs_freep(msg);
|
||||
}
|
||||
|
||||
// The chunk size is sent separately before chunk content.
|
||||
if (true) {
|
||||
MockMSegmentsReader io;
|
||||
io.append(mock_http_response2(200, "0d\r\n"));
|
||||
io.append("Hello, world!\r\n0\r\n\r\n");
|
||||
|
||||
SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false));
|
||||
ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg));
|
||||
|
||||
char buf[32]; ssize_t nread = 0;
|
||||
ISrsHttpResponseReader* r = msg->body_reader();
|
||||
|
||||
HELPER_ARRAY_INIT(buf, sizeof(buf), 0);
|
||||
HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread));
|
||||
EXPECT_EQ(13, nread);
|
||||
EXPECT_STREQ("Hello, world!", buf);
|
||||
|
||||
srs_freep(msg);
|
||||
}
|
||||
|
||||
// If buffer is smaller than chunk, we could read N times to get the whole chunk.
|
||||
if (true) {
|
||||
MockBufferIO io; io.append(mock_http_response2(200, "0d\r\nHello, world!\r\n0\r\n\r\n"));
|
||||
SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false));
|
||||
ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg));
|
||||
|
||||
char buf[32]; ssize_t nread = 0;
|
||||
ISrsHttpResponseReader* r = msg->body_reader();
|
||||
|
||||
HELPER_ARRAY_INIT(buf, sizeof(buf), 0);
|
||||
HELPER_ASSERT_SUCCESS(r->read(buf, 5, &nread));
|
||||
EXPECT_EQ(5, nread);
|
||||
EXPECT_STREQ("Hello", buf);
|
||||
|
||||
HELPER_ARRAY_INIT(buf, sizeof(buf), 0);
|
||||
HELPER_ASSERT_SUCCESS(r->read(buf, 7, &nread));
|
||||
EXPECT_EQ(7, nread);
|
||||
EXPECT_STREQ(", world", buf);
|
||||
|
||||
HELPER_ARRAY_INIT(buf, sizeof(buf), 0);
|
||||
HELPER_ASSERT_SUCCESS(r->read(buf, 7, &nread));
|
||||
EXPECT_EQ(1, nread);
|
||||
EXPECT_STREQ("!", buf);
|
||||
|
||||
HELPER_ASSERT_SUCCESS(r->read(buf, 7, &nread));
|
||||
EXPECT_EQ(0, nread);
|
||||
|
||||
srs_freep(msg);
|
||||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtocolHTTPTest, ClientRequest)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
@ -1157,57 +1398,6 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
|
|||
}
|
||||
}
|
||||
|
||||
class MockMSegmentsReader : public ISrsReader
|
||||
{
|
||||
public:
|
||||
vector<string> in_bytes;
|
||||
public:
|
||||
MockMSegmentsReader();
|
||||
virtual ~MockMSegmentsReader();
|
||||
public:
|
||||
virtual srs_error_t read(void* buf, size_t size, ssize_t* nread);
|
||||
};
|
||||
|
||||
MockMSegmentsReader::MockMSegmentsReader()
|
||||
{
|
||||
}
|
||||
|
||||
MockMSegmentsReader::~MockMSegmentsReader()
|
||||
{
|
||||
}
|
||||
|
||||
srs_error_t MockMSegmentsReader::read(void* buf, size_t size, ssize_t* nread)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
for (;;) {
|
||||
if (in_bytes.empty() || size <= 0) {
|
||||
return srs_error_new(-1, "EOF");
|
||||
}
|
||||
|
||||
string v = in_bytes[0];
|
||||
if (v.empty()) {
|
||||
in_bytes.erase(in_bytes.begin());
|
||||
continue;
|
||||
}
|
||||
|
||||
int nn = srs_min(size, v.length());
|
||||
memcpy(buf, v.data(), nn);
|
||||
if (nread) {
|
||||
*nread = nn;
|
||||
}
|
||||
|
||||
if (nn < (int)v.length()) {
|
||||
in_bytes[0] = string(v.data() + nn, v.length() - nn);
|
||||
} else {
|
||||
in_bytes.erase(in_bytes.begin());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
VOID TEST(ProtocolHTTPTest, MSegmentsReader)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
|
|
@ -2722,6 +2722,12 @@ VOID TEST(KernelErrorTest, CoverAll)
|
|||
srs_freep(err);
|
||||
}
|
||||
|
||||
if (true) {
|
||||
srs_error_t err = srs_error_new(ERROR_HTTP_STREAM_EOF, "graceful close error");
|
||||
EXPECT_TRUE(srs_is_server_gracefully_close(err));
|
||||
srs_freep(err);
|
||||
}
|
||||
|
||||
if (true) {
|
||||
srs_error_t err = srs_error_wrap(srs_error_new(ERROR_CONTROL_RTMP_CLOSE, "control error"), "wrapped");
|
||||
EXPECT_TRUE(srs_error_desc(err) != "");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue