Merge branch 'master' into fix_remote_http

This commit is contained in:
Isaac Connor
2020-02-19 14:42:24 -05:00
685 changed files with 53885 additions and 34197 deletions

View File

@@ -35,6 +35,14 @@
#include <netinet/in.h>
#endif
#if HAVE_LIBPCRE
static RegExpr *header_expr = 0;
static RegExpr *status_expr = 0;
static RegExpr *connection_expr = 0;
static RegExpr *content_length_expr = 0;
static RegExpr *content_type_expr = 0;
#endif
RemoteCameraHttp::RemoteCameraHttp(
unsigned int p_monitor_id,
const std::string &p_method,
@@ -72,30 +80,25 @@ RemoteCameraHttp::RemoteCameraHttp(
if ( p_method == "simple" )
method = SIMPLE;
else if ( p_method == "regexp" )
else if ( p_method == "regexp" ) {
method = REGEXP;
else
} else
Fatal( "Unrecognised method '%s' when creating HTTP camera %d", p_method.c_str(), monitor_id );
if ( capture )
{
if ( capture ) {
Initialise();
}
}
RemoteCameraHttp::~RemoteCameraHttp()
{
if ( capture )
{
RemoteCameraHttp::~RemoteCameraHttp() {
if ( capture ) {
Terminate();
}
}
void RemoteCameraHttp::Initialise()
{
void RemoteCameraHttp::Initialise() {
RemoteCamera::Initialise();
if ( request.empty() )
{
if ( request.empty() ) {
request = stringtf( "GET %s HTTP/%s\r\n", path.c_str(), config.http_version );
request += stringtf( "User-Agent: %s/%s\r\n", config.http_ua, ZM_VERSION );
request += stringtf( "Host: %s\r\n", host.c_str());
@@ -107,8 +110,7 @@ void RemoteCameraHttp::Initialise()
Debug( 2, "Request: %s", request.c_str() );
}
if ( !timeout.tv_sec )
{
if ( !timeout.tv_sec ) {
timeout.tv_sec = config.http_timeout/1000;
timeout.tv_usec = (config.http_timeout%1000)*1000;
}
@@ -120,10 +122,25 @@ void RemoteCameraHttp::Initialise()
mode = SINGLE_IMAGE;
format = UNDEF;
state = HEADER;
}
#if HAVE_LIBPCRE
if ( method == REGEXP ) {
if ( !header_expr )
header_expr = new RegExpr("^(.+?\r?\n\r?\n)", PCRE_DOTALL);
if ( !status_expr )
status_expr = new RegExpr("^HTTP/(1\\.[01]) +([0-9]+) +(.+?)\r?\n", PCRE_CASELESS);
if ( !connection_expr )
connection_expr = new RegExpr("Connection: ?(.+?)\r?\n", PCRE_CASELESS);
if ( !content_length_expr )
content_length_expr = new RegExpr("Content-length: ?([0-9]+)\r?\n", PCRE_CASELESS);
if ( !content_type_expr )
content_type_expr = new RegExpr("Content-type: ?(.+?)(?:; ?boundary=\x22?(.+?)\x22?)?\r?\n", PCRE_CASELESS);
}
#endif
} // end void RemoteCameraHttp::Initialise()
int RemoteCameraHttp::Connect() {
struct addrinfo *p;
struct addrinfo *p = NULL;
for ( p = hp; p != NULL; p = p->ai_next ) {
sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
@@ -157,27 +174,24 @@ int RemoteCameraHttp::Connect() {
return sd;
} // end int RemoteCameraHttp::Connect()
int RemoteCameraHttp::Disconnect()
{
close( sd );
int RemoteCameraHttp::Disconnect() {
close(sd);
sd = -1;
Debug( 3, "Disconnected from host" );
return( 0 );
Debug(3, "Disconnected from host");
return 0;
}
int RemoteCameraHttp::SendRequest()
{
Debug( 2, "Sending request: %s", request.c_str() );
if ( write( sd, request.data(), request.length() ) < 0 )
{
Error( "Can't write: %s", strerror(errno) );
int RemoteCameraHttp::SendRequest() {
Debug(2, "Sending request: %s", request.c_str());
if ( write(sd, request.data(), request.length()) < 0 ) {
Error("Can't write: %s", strerror(errno));
Disconnect();
return( -1 );
return -1;
}
format = UNDEF;
state = HEADER;
Debug( 3, "Request sent" );
return( 0 );
Debug(3, "Request sent");
return 0;
}
/* Return codes are as follows:
@@ -273,9 +287,9 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) {
total_bytes_to_read -= bytes_read;
} while ( total_bytes_to_read );
Debug( 4, buffer );
Debug(4, buffer);
return( total_bytes_read );
return total_bytes_read;
}
int RemoteCameraHttp::GetData() {
@@ -290,12 +304,10 @@ int RemoteCameraHttp::GetData() {
return buffer_len;
}
int RemoteCameraHttp::GetResponse()
{
int RemoteCameraHttp::GetResponse() {
int buffer_len;
#if HAVE_LIBPCRE
if ( method == REGEXP )
{
if ( method == REGEXP ) {
const char *header = 0;
int header_len = 0;
const char *http_version = 0;
@@ -310,34 +322,21 @@ int RemoteCameraHttp::GetResponse()
//int subcontent_length = 0;
//const char *subcontent_type = "";
while ( true )
{
switch( state )
{
while ( !zm_terminate ) {
switch( state ) {
case HEADER :
{
static RegExpr *header_expr = 0;
static RegExpr *status_expr = 0;
static RegExpr *connection_expr = 0;
static RegExpr *content_length_expr = 0;
static RegExpr *content_type_expr = 0;
buffer_len = GetData();
if ( buffer_len < 0 ) {
Error( "Unable to read header data" );
return( -1 );
Error("Unable to read header data");
return -1;
}
bytes += buffer_len;
if ( !header_expr )
header_expr = new RegExpr( "^(.+?\r?\n\r?\n)", PCRE_DOTALL );
if ( header_expr->Match( (char*)buffer, buffer.size() ) == 2 )
{
if ( header_expr->Match( (char*)buffer, buffer.size() ) == 2 ) {
header = header_expr->MatchString( 1 );
header_len = header_expr->MatchLength( 1 );
Debug( 4, "Captured header (%d bytes):\n'%s'", header_len, header );
Debug(4, "Captured header (%d bytes):\n'%s'", header_len, header);
if ( !status_expr )
status_expr = new RegExpr( "^HTTP/(1\\.[01]) +([0-9]+) +(.+?)\r?\n", PCRE_CASELESS );
if ( status_expr->Match( header, header_len ) < 4 )
{
Error( "Unable to extract HTTP status from header" );
@@ -376,24 +375,18 @@ int RemoteCameraHttp::GetResponse()
}
Debug( 3, "Got status '%d' (%s), http version %s", status_code, status_mesg, http_version );
if ( !connection_expr )
connection_expr = new RegExpr( "Connection: ?(.+?)\r?\n", PCRE_CASELESS );
if ( connection_expr->Match( header, header_len ) == 2 )
{
connection_type = connection_expr->MatchString( 1 );
Debug( 3, "Got connection '%s'", connection_type );
}
if ( !content_length_expr )
content_length_expr = new RegExpr( "Content-length: ?([0-9]+)\r?\n", PCRE_CASELESS );
if ( content_length_expr->Match( header, header_len ) == 2 )
{
content_length = atoi( content_length_expr->MatchString( 1 ) );
Debug( 3, "Got content length '%d'", content_length );
}
if ( !content_type_expr )
content_type_expr = new RegExpr( "Content-type: ?(.+?)(?:; ?boundary=\x22?(.+?)\x22?)?\r?\n", PCRE_CASELESS );
if ( content_type_expr->Match( header, header_len ) >= 2 )
{
content_type = content_type_expr->MatchString( 1 );
@@ -573,17 +566,14 @@ int RemoteCameraHttp::GetResponse()
}
}
}
if ( mode == SINGLE_IMAGE )
{
if ( mode == SINGLE_IMAGE ) {
state = HEADER;
Disconnect();
}
else
{
} else {
state = SUBHEADER;
}
Debug( 3, "Returning %d (%d) bytes of captured content", content_length, buffer.size() );
return( content_length );
return content_length;
}
case HEADERCONT :
case SUBHEADERCONT :
@@ -593,8 +583,7 @@ int RemoteCameraHttp::GetResponse()
}
}
}
}
else
} else
#endif // HAVE_LIBPCRE
{
static const char *http_match = "HTTP/";
@@ -647,7 +636,7 @@ int RemoteCameraHttp::GetResponse()
static char content_boundary[64];
static int content_boundary_len;
while ( true ) {
while ( !zm_terminate ) {
switch( state ) {
case HEADER :
{
@@ -671,8 +660,8 @@ int RemoteCameraHttp::GetResponse()
{
buffer_len = GetData();
if ( buffer_len < 0 ) {
Error( "Unable to read header" );
return( -1 );
Error("Unable to read header");
return -1;
}
bytes += buffer_len;
@@ -682,9 +671,10 @@ int RemoteCameraHttp::GetResponse()
bool all_headers = false;
while( true ) {
int crlf_len = memspn( header_ptr, "\r\n", header_len );
int crlf_len = memspn(header_ptr, "\r\n", header_len);
if ( n_headers ) {
if ( (crlf_len == 2 && !strncmp( header_ptr, "\n\n", crlf_len )) || (crlf_len == 4 && !strncmp( header_ptr, "\r\n\r\n", crlf_len )) ) {
Debug(3, "Have double linefeed, done headers");
*header_ptr = '\0';
header_ptr += crlf_len;
header_len -= buffer.consume( header_ptr-(char *)buffer );
@@ -744,7 +734,7 @@ int RemoteCameraHttp::GetResponse()
start_ptr = http_header;
end_ptr = start_ptr+strspn( start_ptr, "10." );
// FIXME WHy are we memsetting every time? Can we not do it once?
// FIXME Why are we memsetting every time? Can we not do it once?
memset( http_version, 0, sizeof(http_version) );
strncpy( http_version, start_ptr, end_ptr-start_ptr );
@@ -828,7 +818,7 @@ int RemoteCameraHttp::GetResponse()
strcpy( content_type, start_ptr );
Debug( 3, "Got content type '%s'", content_type );
}
}
} // end if content_type_header
if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) ) {
// Single image
@@ -863,10 +853,10 @@ int RemoteCameraHttp::GetResponse()
return( -1 );
}
} else {
Debug( 3, "Unable to extract entire header from stream, continuing" );
Debug(3, "Unable to extract entire header from stream, continuing");
state = HEADERCONT;
//return( -1 );
}
} // end if all_headers
break;
}
case SUBHEADER :
@@ -1071,7 +1061,6 @@ int RemoteCameraHttp::PreCapture() {
if ( sd < 0 ) {
Connect();
if ( sd < 0 ) {
Error("Unable to connect to camera");
return -1;
}
mode = SINGLE_IMAGE;
@@ -1079,12 +1068,12 @@ int RemoteCameraHttp::PreCapture() {
}
if ( mode == SINGLE_IMAGE ) {
if ( SendRequest() < 0 ) {
Error( "Unable to send request" );
Error("Unable to send request");
Disconnect();
return( -1 );
return -1;
}
}
return( 0 );
return 0;
}
int RemoteCameraHttp::Capture( Image &image ) {