예제 #1
0
/**
 * parse a single line of the TivoConnect protocol into a 'kkv' structure
 * "foo=bar\x0a"
 * "AAABCCCDDDD"
 */
static ptrdiff_t do_parse_kv(char *buf, size_t len, kkv *k)
{
  const char *orig = buf; /* save original address */
  size_t l = memcspn(buf, len, "=\x0a", 2);
  k->keystr.start = buf;
  k->keystr.len = l;
  strlower(k->keystr.start, k->keystr.len);
  k->key = str2key(&k->keystr);
  buf += l, len -= l;
  l = memspn(buf, len, "=", 1);
  buf += l, len -= l;
  k->val.start = buf;
  l = memcspn(buf, len, "\x0a", 1);
  k->val.len = l;
  buf += l, len -= l;
  l = memspn(buf, len, "\x0a", 1);
  buf += l, len -= l;
  return buf - orig;
}
예제 #2
0
파일: http.c 프로젝트: aNeutrino/lanmap2
/**
 * 'buf' points at first char in headers, parse them into 'head' and
 * return bytes consumed
 * @note this function is used by other protocols, such as SSDP
 */
size_t http_parse_headers(char *buf, size_t len, http_headers *head)
{
  struct head_kv *kv = head->h;
  const char *orig = buf,
             *end = buf + len;
  size_t skip = 2;
  head->cnt = 0;
  /* FIXME: make sure we don't go further than 'len' */
#if 0
  printf("%s len=%u buf=%.*s\n",
    __func__, (unsigned)len, (unsigned)len, buf);
#endif
  while (
    buf < end
    && 2 == skip
    && head->cnt < sizeof head->h / sizeof head->h[0]
  ) {
    /* "<A><: ><B><\r\n>" */
    ptrlen_list *pl = &kv->val;
    ptrlen *v = pl->p;
    pl->cnt = 0;
    kv->key.start = buf;
    kv->key.len = memcspn(buf, len, ": \r\n", 4);
    buf += kv->key.len;
    len -= kv->key.len;
    skip = memspn(buf, len, ": ", 2);
    buf += skip;
    len -= skip;
    v->start = buf;
    v->len = memcspn(buf, len, "\r\n", 2);
    pl->cnt++;
    buf += v->len;
    len -= v->len;
    skip = memspn(buf, len, "\r\n", 2);
    buf += skip;
    len -= skip;
    head->cnt++;
    v++;
    kv++;
  }
  return (size_t)(buf - orig);
}
예제 #3
0
파일: http.c 프로젝트: aNeutrino/lanmap2
// FIXME: "GET /common/jquery.autocomplete.js HTTP/1.1\x0d\x0a" -> HTTP req meth=HTT uri=/1.1 304 Not Modified
static ptrdiff_t do_parse_req(char *buf, size_t len, http_req *r)
{
  const char *orig = buf;
  size_t l = memcspn(buf, len, " \r\n", 3);
  if (l > 0) {
    /* method */
    r->meth.start = buf;
    r->meth.len = l;
    buf += l, len -= l;
    /* skip whitespace */
    l = memspn(buf, len, " ", 1);
    buf += l, len -= l;
    /* uri */
    l = memcspn(buf, len, " \r\n", 3);
    r->uri.start = buf;
    r->uri.len = l;
    buf += l, len -= l;
    /* skip whitespace */
    l = memspn(buf, len, " ", 1);
    buf += l, len -= l;
    /* version */
    l = memcspn(buf, len, "\r\n", 2);
    r->ver.start = buf;
    r->ver.len = l;
    printf("HTTP meth=<%.*s> uri=<%.*s> ver=<%.*s> (%u)\n",
      (int)r->meth.len, r->meth.start,
      (int)r->uri.len, r->uri.start,
      (int)r->ver.len, r->ver.start, r->ver.len);
    buf += l, len -= l;
    /* skip newline */
    /* NOTE: we must skip only a single set of "\r\n" */
    if (len >= 2 && '\r' == buf[0] && '\n' == buf[1])
      buf += 2, len -= 2;
  }
#if 1
  /* debug */
  printf("%s ver=<%.*s> buf=<%.*s>\n",
    __func__, (int)r->ver.len, r->ver.start, 20, buf);
  printf("%s -> %u\n", __func__, (unsigned)(buf-orig));
#endif
  return buf - orig;
}
예제 #4
0
int RemoteCameraHttp::GetResponse()
{
#if HAVE_LIBPCRE
    if ( method == REGEXP )
    {
        const char *header = 0;
        int header_len = 0;
        const char *http_version = 0;
        int status_code = 0;
        const char *status_mesg = 0;
        const char *connection_type = "";
        int content_length = 0;
        const char *content_type = "";
        const char *content_boundary = "";
        const char *subheader = 0;
        int subheader_len = 0;
        //int subcontent_length = 0;
        //const char *subcontent_type = "";

        while ( true )
        {
            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;

                    int buffer_len = ReadData( buffer );
                    if ( buffer_len == 0 )
                    {
                        Error( "Connection dropped by remote end" );
                        return( 0 );
                    }
                    else if ( buffer_len < 0 )
                    {
                        Error( "Unable to read header data" );
                        return( -1 );
                    }
                    if ( !header_expr )
                        header_expr = new RegExpr( "^(.+?\r?\n\r?\n)", PCRE_DOTALL );
                    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 );

                        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" );
                            return( -1 );
                        }
                        http_version = status_expr->MatchString( 1 );
                        status_code = atoi( status_expr->MatchString( 2 ) );
                        status_mesg = status_expr->MatchString( 3 );

                        if ( status_code < 200 || status_code > 299 )
                        {
                            Error( "Invalid response status %d: %s", status_code, status_mesg );
                            return( -1 );
                        }
                        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=(.+?))?\r?\n", PCRE_CASELESS );
                        if ( content_type_expr->Match( header, header_len ) >= 2 )
                        {
                            content_type = content_type_expr->MatchString( 1 );
                            Debug( 3, "Got content type '%s'\n", content_type );
                            if ( content_type_expr->MatchCount() > 2 )
                            {
                                content_boundary = content_type_expr->MatchString( 2 );
                                Debug( 3, "Got content boundary '%s'", content_boundary );
                            }
                        }

                        if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) )
                        {
                            // Single image
                            mode = SINGLE_IMAGE;
                            format = JPEG;
                            state = CONTENT;
                        }
                        else if ( !strcasecmp( content_type, "image/x-rgb" ) )
                        {
                            // Single image
                            mode = SINGLE_IMAGE;
                            format = X_RGB;
                            state = CONTENT;
                        }
                        else if ( !strcasecmp( content_type, "image/x-rgbz" ) )
                        {
                            // Single image
                            mode = SINGLE_IMAGE;
                            format = X_RGBZ;
                            state = CONTENT;
                        }
                        else if ( !strcasecmp( content_type, "multipart/x-mixed-replace" ) )
                        {
                            // Image stream, so start processing
                            if ( !content_boundary[0] )
                            {
                                Error( "No content boundary found in header '%s'", header );
                                return( -1 );
                            }
                            mode = MULTI_IMAGE;
                            state = SUBHEADER;
                        }
                        //else if ( !strcasecmp( content_type, "video/mpeg" ) || !strcasecmp( content_type, "video/mpg" ) )
                        //{
                            //// MPEG stream, coming soon!
                        //}
                        else
                        {
                            Error( "Unrecognised content type '%s'", content_type );
                            return( -1 );
                        }
                        buffer.consume( header_len );
                    }
                    else
                    {
                        Debug( 3, "Unable to extract header from stream, retrying" );
                        //return( -1 );
                    }
                    break;
                }
                case SUBHEADER :
                {
                    static RegExpr *subheader_expr = 0;
                    static RegExpr *subcontent_length_expr = 0;
                    static RegExpr *subcontent_type_expr = 0;

                    if ( !subheader_expr )
                    {
                        char subheader_pattern[256] = "";
                        snprintf( subheader_pattern, sizeof(subheader_pattern), "^((?:\r?\n){0,2}?(?:--)?%s\r?\n.+?\r?\n\r?\n)", content_boundary );
                        subheader_expr = new RegExpr( subheader_pattern, PCRE_DOTALL );
                    }
                    if ( subheader_expr->Match( (char *)buffer, (int)buffer ) == 2 )
                    {
                        subheader = subheader_expr->MatchString( 1 );
                        subheader_len = subheader_expr->MatchLength( 1 );
                        Debug( 4, "Captured subheader (%d bytes):'%s'", subheader_len, subheader );

                        if ( !subcontent_length_expr )
                            subcontent_length_expr = new RegExpr( "Content-length: ?([0-9]+)\r?\n", PCRE_CASELESS );
                        if ( subcontent_length_expr->Match( subheader, subheader_len ) == 2 )
                        {
                            content_length = atoi( subcontent_length_expr->MatchString( 1 ) );
                            Debug( 3, "Got subcontent length '%d'", content_length );
                        }

                        if ( !subcontent_type_expr )
                            subcontent_type_expr = new RegExpr( "Content-type: ?(.+?)\r?\n", PCRE_CASELESS );
                        if ( subcontent_type_expr->Match( subheader, subheader_len ) == 2 )
                        {
                            content_type = subcontent_type_expr->MatchString( 1 );
                            Debug( 3, "Got subcontent type '%s'", content_type );
                        }

                        buffer.consume( subheader_len );
                        state = CONTENT;
                    }
                    else
                    {
                        Debug( 3, "Unable to extract subheader from stream, retrying" );
                        int buffer_len = ReadData( buffer );
                        if ( buffer_len == 0 )
                        {
                            Error( "Connection dropped by remote end" );
                            return( 0 );
                        }
                        else if ( buffer_len < 0 )
                        {
                            return( -1 );
                        }
                    }
                    break;
                }
                case CONTENT :
                {
                    if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) )
                    {
                        format = JPEG;
                    }
                    else if ( !strcasecmp( content_type, "image/x-rgb" ) )
                    {
                        format = X_RGB;
                    }
                    else if ( !strcasecmp( content_type, "image/x-rgbz" ) )
                    {
                        format = X_RGBZ;
                    }
                    else
                    {
                        Error( "Found unsupported content type '%s'", content_type );
                        return( -1 );
                    }

                    if ( content_length )
                    {
                        while ( buffer.size() < (unsigned int)content_length )
                        {
                            int buffer_len = ReadData( buffer );
                            if ( buffer_len == 0 )
                            {
                                Error( "Connection dropped by remote end" );
                                return( 0 );
                            }
                            else if ( buffer_len < 0 )
                            {
                                Error( "Unable to read content" );
                                return( -1 );
                            }
                        }
                        Debug( 3, "Got end of image by length, content-length = %d", content_length );
                    }
                    else
                    {
                        while ( !content_length )
                        {
                            int buffer_len = ReadData( buffer );
                            if ( buffer_len == 0 )
                            {
                                if ( mode == MULTI_IMAGE )
                                {
                                    Error( "Connection dropped by remote end" );
                                    return( 0 );
                                }
                            }
                            else if ( buffer_len < 0 )
                            {
                                Error( "Unable to read content" );
                                return( -1 );
                            }
                            static RegExpr *content_expr = 0;
                            if ( buffer_len )
                            {
                                if ( mode == MULTI_IMAGE )
                                {
                                    if ( !content_expr )
                                    {
                                        char content_pattern[256] = "";
                                        snprintf( content_pattern, sizeof(content_pattern), "^(.+?)(?:\r?\n)*(?:--)?%s\r?\n", content_boundary );
                                        content_expr = new RegExpr( content_pattern, PCRE_DOTALL );
                                    }
                                    if ( content_expr->Match( buffer, buffer.size() ) == 2 )
                                    {
                                        content_length = content_expr->MatchLength( 1 );
                                        Debug( 3, "Got end of image by pattern, content-length = %d", content_length );
                                    }
                                }
                            }
                            else
                            {
                                content_length = buffer.size();
                                Debug( 3, "Got end of image by closure, content-length = %d", content_length );
                                if ( mode == SINGLE_IMAGE )
                                {
                                    if ( !content_expr )
                                    {
                                        content_expr = new RegExpr( "^(.+?)(?:\r?\n){1,2}?$", PCRE_DOTALL );
                                    }
                                    if ( content_expr->Match( buffer, buffer.size() ) == 2 )
                                    {
                                        content_length = content_expr->MatchLength( 1 );
                                        Debug( 3, "Trimmed end of image, new content-length = %d", content_length );
                                    }
                                }
                            }
                        }
                    }
                    if ( mode == SINGLE_IMAGE )
                    {
                        state = HEADER;
                        Disconnect();
                    }
                    else
                    {
                        state = SUBHEADER;
                    }
                    Debug( 3, "Returning %d (%d) bytes of captured content", content_length, buffer.size() );
                    return( content_length );
                }
                case HEADERCONT :
                case SUBHEADERCONT :
                {
                    // Ignore
                    break;
                }
            }
        }
    }
    else
#endif // HAVE_LIBPCRE
    {
        if ( method == REGEXP )
        {
            Warning( "Unable to use netcam regexps as not compiled with libpcre" );
        }
        static const char *http_match = "HTTP/";
        static const char *connection_match = "Connection:";
        static const char *content_length_match = "Content-length:";
        static const char *content_type_match = "Content-type:";
        static const char *boundary_match = "boundary=";
        static int http_match_len = 0;
        static int connection_match_len = 0;
        static int content_length_match_len = 0;
        static int content_type_match_len = 0;
        static int boundary_match_len = 0;

        if ( !http_match_len )
            http_match_len = strlen( http_match );
        if ( !connection_match_len )
            connection_match_len = strlen( connection_match );
        if ( !content_length_match_len )
            content_length_match_len = strlen( content_length_match );
        if ( !content_type_match_len )
            content_type_match_len = strlen( content_type_match );
        if ( !boundary_match_len )
            boundary_match_len = strlen( boundary_match );

        static int n_headers;
        //static char *headers[32];

        static int n_subheaders;
        //static char *subheaders[32];

        static char *http_header;
        static char *connection_header;
        static char *content_length_header;
        static char *content_type_header;
        static char *boundary_header;
        static char subcontent_length_header[32];
        static char subcontent_type_header[64];
    
        static char http_version[16];
        static char status_code[16];
        //static int status;
        static char status_mesg[256];
        static char connection_type[32];
        static int content_length;
        static char content_type[32];
        static char content_boundary[64];
        static int content_boundary_len;

        while ( true )
        {
            switch( state )
            {
                case HEADER :
                {
                    n_headers = 0;
                    http_header = 0;
                    connection_header = 0;
                    content_length_header = 0;
                    content_type_header = 0;

                    http_version[0] = '\0';
                    status_code [0]= '\0';
                    //status = 0;
                    status_mesg [0]= '\0';
                    connection_type [0]= '\0';
                    content_length = 0;
                    content_type[0] = '\0';
                    content_boundary[0] = '\0';
                    content_boundary_len = 0;
                }
                case HEADERCONT :
                {
                    int buffer_len = ReadData( buffer );
                    if ( buffer_len == 0 )
                    {
                        Error( "Connection dropped by remote end" );
                        return( 0 );
                    }
                    else if ( buffer_len < 0 )
                    {
                        Error( "Unable to read header" );
                        return( -1 );
                    }

                    char *crlf = 0;
                    char *header_ptr = (char *)buffer;
                    int header_len = buffer.size();
                    bool all_headers = false;

                    while( true )
                    {
                        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 )) )
                            {
                                *header_ptr = '\0';
                                header_ptr += crlf_len;
                                header_len -= buffer.consume( header_ptr-(char *)buffer );
                                all_headers = true;
                                break;
                            }
                        }
                        if ( crlf_len )
                        {
                            if ( header_len == crlf_len )
                            {
                                break;
                            }
                            else
                            {
                                *header_ptr = '\0';
                                header_ptr += crlf_len;
                                header_len -= buffer.consume( header_ptr-(char *)buffer );
                            }
                        }

                        Debug( 6, "%s", header_ptr );
                        if ( (crlf = mempbrk( header_ptr, "\r\n", header_len )) )
                        {
                            //headers[n_headers++] = header_ptr;
                            n_headers++;

                            if ( !http_header && (strncasecmp( header_ptr, http_match, http_match_len ) == 0) )
                            {
                                http_header = header_ptr+http_match_len;
                                Debug( 6, "Got http header '%s'", header_ptr );
                            }
                            else if ( !connection_header && (strncasecmp( header_ptr, connection_match, connection_match_len) == 0) )
                            {
                                connection_header = header_ptr+connection_match_len;
                                Debug( 6, "Got connection header '%s'", header_ptr );
                            }
                            else if ( !content_length_header && (strncasecmp( header_ptr, content_length_match, content_length_match_len) == 0) )
                            {
                                content_length_header = header_ptr+content_length_match_len;
                                Debug( 6, "Got content length header '%s'", header_ptr );
                            }
                            else if ( !content_type_header && (strncasecmp( header_ptr, content_type_match, content_type_match_len) == 0) )
                            {
                                content_type_header = header_ptr+content_type_match_len;
                                Debug( 6, "Got content type header '%s'", header_ptr );
                            }
                            else
                            {
                                Debug( 6, "Got ignored header '%s'", header_ptr );
                            }
                            header_ptr = crlf;
                            header_len -= buffer.consume( header_ptr-(char *)buffer );
                        }
                        else
                        {
                            // No end of line found
                            break;
                        }
                    }

                    if ( all_headers )
                    {
                        char *start_ptr, *end_ptr;

                        if ( !http_header )
                        {
                            Error( "Unable to extract HTTP status from header" );
                            return( -1 );
                        }

                        start_ptr = http_header;
                        end_ptr = start_ptr+strspn( start_ptr, "10." );

                        memset( http_version, 0, sizeof(http_version) );
                        strncpy( http_version, start_ptr, end_ptr-start_ptr );

                        start_ptr = end_ptr;
                        start_ptr += strspn( start_ptr, " " );
                        end_ptr = start_ptr+strspn( start_ptr, "0123456789" );

                        memset( status_code, 0, sizeof(status_code) );
                        strncpy( status_code, start_ptr, end_ptr-start_ptr );
                        int status = atoi( status_code );

                        start_ptr = end_ptr;
                        start_ptr += strspn( start_ptr, " " );
                        strcpy( status_mesg, start_ptr );

                        if ( status < 200 || status > 299 )
                        {
                            Error( "Invalid response status %s: %s", status_code, status_mesg );
                            return( -1 );
                        }
                        Debug( 3, "Got status '%d' (%s), http version %s", status, status_mesg, http_version );

                        if ( connection_header )
                        {
                            memset( connection_type, 0, sizeof(connection_type) );
                            start_ptr = connection_header + strspn( connection_header, " " );
                            strcpy( connection_type, start_ptr );
                            Debug( 3, "Got connection '%s'", connection_type );
                        }
                        if ( content_length_header )
                        {
                            start_ptr = content_length_header + strspn( content_length_header, " " );
                            content_length = atoi( start_ptr );
                            Debug( 3, "Got content length '%d'", content_length );
                        }
                        if ( content_type_header )
                        {
                            memset( content_type, 0, sizeof(content_type) );
                            start_ptr = content_type_header + strspn( content_type_header, " " );
                            if ( (end_ptr = strchr( start_ptr, ';' )) )
                            {
                                strncpy( content_type, start_ptr, end_ptr-start_ptr );
                                Debug( 3, "Got content type '%s'", content_type );

                                start_ptr = end_ptr + strspn( end_ptr, "; " );

                                if ( strncasecmp( start_ptr, boundary_match, boundary_match_len ) == 0 )
                                {
                                    start_ptr += boundary_match_len;
                                    start_ptr += strspn( start_ptr, "-" );
                                    content_boundary_len = sprintf( content_boundary, "--%s", start_ptr );
                                    Debug( 3, "Got content boundary '%s'", content_boundary );
                                }
                                else
                                {
                                    Error( "No content boundary found in header '%s'", content_type_header );
                                }
                            }
                            else
                            {
                                strcpy( content_type, start_ptr );
                                Debug( 3, "Got content type '%s'", content_type );
                            }
                        }

                        if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) )
                        {
                            // Single image
                            mode = SINGLE_IMAGE;
                            format = JPEG;
                            state = CONTENT;
                        }
                        else if ( !strcasecmp( content_type, "image/x-rgb" ) )
                        {
                            // Single image
                            mode = SINGLE_IMAGE;
                            format = X_RGB;
                            state = CONTENT;
                        }
                        else if ( !strcasecmp( content_type, "image/x-rgbz" ) )
                        {
                            // Single image
                            mode = SINGLE_IMAGE;
                            format = X_RGBZ;
                            state = CONTENT;
                        }
                        else if ( !strcasecmp( content_type, "multipart/x-mixed-replace" ) )
                        {
                            // Image stream, so start processing
                            if ( !content_boundary[0] )
                            {
                                Error( "No content boundary found in header '%s'", content_type_header );
                                return( -1 );
                            }
                            mode = MULTI_IMAGE;
                            state = SUBHEADER;
                        }
                        //else if ( !strcasecmp( content_type, "video/mpeg" ) || !strcasecmp( content_type, "video/mpg" ) )
                        //{
                            //// MPEG stream, coming soon!
                        //}
                        else
                        {
                            Error( "Unrecognised content type '%s'", content_type );
                            return( -1 );
                        }
                    }
                    else
                    {
                        Debug( 3, "Unable to extract entire header from stream, continuing" );
                        state = HEADERCONT;
                        //return( -1 );
                    }
                    break;
                }
                case SUBHEADER :
                {
                    n_subheaders = 0;
                    boundary_header = 0;
                    subcontent_length_header[0] = '\0';
                    subcontent_type_header[0] = '\0';
                    content_length = 0;
                    content_type[0] = '\0';
                }
                case SUBHEADERCONT :
                {
                    char *crlf = 0;
                    char *subheader_ptr = (char *)buffer;
                    int subheader_len = buffer.size();
                    bool all_headers = false;

                    while( true )
                    {
                        int crlf_len = memspn( subheader_ptr, "\r\n", subheader_len );
                        if ( n_subheaders )
                        {
                            if ( (crlf_len == 2 && !strncmp( subheader_ptr, "\n\n", crlf_len )) || (crlf_len == 4 && !strncmp( subheader_ptr, "\r\n\r\n", crlf_len )) )
                            {
                                *subheader_ptr = '\0';
                                subheader_ptr += crlf_len;
                                subheader_len -= buffer.consume( subheader_ptr-(char *)buffer );
                                all_headers = true;
                                break;
                            }
                        }
                        if ( crlf_len )
                        {
                            if ( subheader_len == crlf_len )
                            {
                                break;
                            }
                            else
                            {
                                *subheader_ptr = '\0';
                                subheader_ptr += crlf_len;
                                subheader_len -= buffer.consume( subheader_ptr-(char *)buffer );
                            }
                        }

                        Debug( 6, "%d: %s", subheader_len, subheader_ptr );

                        if ( (crlf = mempbrk( subheader_ptr, "\r\n", subheader_len )) )
                        {
                            //subheaders[n_subheaders++] = subheader_ptr;
                            n_subheaders++;

                            if ( !boundary_header && (strncasecmp( subheader_ptr, content_boundary, content_boundary_len ) == 0) )
                            {
                                boundary_header = subheader_ptr;
                                Debug( 4, "Got boundary subheader '%s'", subheader_ptr );
                            }
                            else if ( !subcontent_length_header[0] && (strncasecmp( subheader_ptr, content_length_match, content_length_match_len) == 0) )
                            {
                                strncpy( subcontent_length_header, subheader_ptr+content_length_match_len, sizeof(subcontent_length_header) );
                                *(subcontent_length_header+strcspn( subcontent_length_header, "\r\n" )) = '\0';
                                Debug( 4, "Got content length subheader '%s'", subcontent_length_header );
                            }
                            else if ( !subcontent_type_header[0] && (strncasecmp( subheader_ptr, content_type_match, content_type_match_len) == 0) )
                            {
                                strncpy( subcontent_type_header, subheader_ptr+content_type_match_len, sizeof(subcontent_type_header) );
                                *(subcontent_type_header+strcspn( subcontent_type_header, "\r\n" )) = '\0';
                                Debug( 4, "Got content type subheader '%s'", subcontent_type_header );
                            }
                            else
                            {
                                Debug( 6, "Got ignored subheader '%s' found", subheader_ptr );
                            }
                            subheader_ptr = crlf;
                            subheader_len -= buffer.consume( subheader_ptr-(char *)buffer );
                        }
                        else
                        {
                            // No line end found
                            break;
                        }
                    }
                    
                    if ( all_headers && boundary_header )
                    {
                        char *start_ptr/*, *end_ptr*/;

                        Debug( 3, "Got boundary '%s'", boundary_header );

                        if ( subcontent_length_header[0] )
                        {
                            start_ptr = subcontent_length_header + strspn( subcontent_length_header, " " );
                            content_length = atoi( start_ptr );
                            Debug( 3, "Got subcontent length '%d'", content_length );
                        }
                        if ( subcontent_type_header[0] )
                        {
                            memset( content_type, 0, sizeof(content_type) );
                            start_ptr = subcontent_type_header + strspn( subcontent_type_header, " " );
                            strcpy( content_type, start_ptr );
                            Debug( 3, "Got subcontent type '%s'", content_type );
                        }
                        state = CONTENT;
                    }
                    else
                    {
                        Debug( 3, "Unable to extract subheader from stream, retrying" );
                        int buffer_len = ReadData( buffer );
                        if ( buffer_len == 0 )
                        {
                            Error( "Connection dropped by remote end" );
                            return( 0 );
                        }
                        else if ( buffer_len < 0 )
                        {
                            Error( "Unable to read subheader" );
                            return( -1 );
                        }
                        state = SUBHEADERCONT;
                    }
                    break;
                }
                case CONTENT :
                {
                    if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) )
                    {
                        format = JPEG;
                    }
                    else if ( !strcasecmp( content_type, "image/x-rgb" ) )
                    {
                        format = X_RGB;
                    }
                    else if ( !strcasecmp( content_type, "image/x-rgbz" ) )
                    {
                        format = X_RGBZ;
                    }
                    else
                    {
                        Error( "Found unsupported content type '%s'", content_type );
                        return( -1 );
                    }

                    if ( format == JPEG && buffer.size() >= 2 )
                    {
                        if ( buffer[0] != 0xff || buffer[1] != 0xd8 )
                        {
                            Error( "Found bogus jpeg header '%02x%02x'", buffer[0], buffer[1] );
                            return( -1 );
                        }
                    }

                    if ( content_length )
                    {
                        while ( buffer.size() < (unsigned int)content_length )
                        {
                            //int buffer_len = ReadData( buffer, content_length-buffer.size() );
                            int buffer_len = ReadData( buffer );
                            if ( buffer_len == 0 )
                            {
                                Error( "Connection dropped by remote end" );
                                return( 0 );
                            }
                            else if ( buffer_len < 0 )
                            {
                                Error( "Unable to read content" );
                                return( -1 );
                            }
                        }
                        Debug( 3, "Got end of image by length, content-length = %d", content_length );
                    }
                    else
                    {
                        int content_pos = 0;
                        while ( !content_length )
                        {
                            int buffer_len = ReadData( buffer );
                            if ( buffer_len == 0 )
                            {
                                if ( mode == MULTI_IMAGE )
                                {
                                    Error( "Connection dropped by remote end" );
                                    return( 0 );
                                }
                            }
                            else if ( buffer_len < 0 )
                            {
                                Error( "Unable to read content" );
                                return( -1 );
                            }
                            int buffer_size = buffer.size();
                            if ( buffer_len )
                            {
                                if ( mode == MULTI_IMAGE )
                                {
                                    while ( char *start_ptr = (char *)memstr( (char *)buffer+content_pos, "\r\n--", buffer_size-content_pos ) )
                                    {
                                        content_length = start_ptr - (char *)buffer;
                                        Debug( 3, "Got end of image by pattern (crlf--), content-length = %d", content_length );
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                content_length = buffer_size;
                                Debug( 3, "Got end of image by closure, content-length = %d", content_length );
                                if ( mode == SINGLE_IMAGE )
                                {
                                    char *end_ptr = (char *)buffer+buffer_size;

                                    while( *end_ptr == '\r' || *end_ptr == '\n' )
                                    {
                                        content_length--;
                                        end_ptr--;
                                    }

                                    if ( end_ptr != ((char *)buffer+buffer_size) )
                                    {
                                        Debug( 3, "Trimmed end of image, new content-length = %d", content_length );
                                    }
                                }
                            }
                        }
                    }
                    if ( mode == SINGLE_IMAGE )
                    {
                        state = HEADER;
                        Disconnect();
                    }
                    else
                    {
                        state = SUBHEADER;
                    }

                    if ( format == JPEG && buffer.size() >= 2 )
                    {
                        if ( buffer[0] != 0xff || buffer[1] != 0xd8 )
                        {
                            Error( "Found bogus jpeg header '%02x%02x'", buffer[0], buffer[1] );
                            return( -1 );
                        }
                    }

                    Debug( 3, "Returning %d (%d) bytes of captured content", content_length, buffer.size() );
                    return( content_length );
                }
            }
        }
    }
    return( 0 );
}
예제 #5
0
int cURLCamera::Capture( Image &image ) {
  bool frameComplete = false;

  /* MODE_STREAM specific variables */
  bool SubHeadersParsingComplete = false;
  unsigned int frame_content_length = 0;
  std::string frame_content_type;
  bool need_more_data = false;
  int nRet;

  /* Grab the mutex to ensure exclusive access to the shared data */
  lock();

  while ( !frameComplete ) {

    /* If the work thread did a reset, reset our local variables */
    if ( bReset ) {
      SubHeadersParsingComplete = false;
      frame_content_length = 0;
      frame_content_type.clear();
      need_more_data = false;
      bReset = false;
    }

    if ( mode == MODE_UNSET ) {
      /* Don't have a mode yet. Sleep while waiting for data */
      nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex);
      if ( nRet != 0 ) {
        Error("Failed waiting for available data condition variable: %s",strerror(nRet));
        return -20;
      }
    }

    if ( mode == MODE_STREAM ) {

      /* Subheader parsing */
      while( !SubHeadersParsingComplete && !need_more_data ) {

        size_t crlf_start, crlf_end, crlf_size;
        std::string subheader;

        /* Check if the buffer contains something */
        if ( databuffer.empty() ) {
          /* Empty buffer, wait for data */
          need_more_data = true;
          break;
        }
     
        /* Find crlf start */
        crlf_start = memcspn(databuffer,"\r\n",databuffer.size());
        if ( crlf_start == databuffer.size() ) {
          /* Not found, wait for more data */
          need_more_data = true;
          break;
        }

        /* See if we have enough data for determining crlf length */
        if ( databuffer.size() < crlf_start+5 ) {
          /* Need more data */
          need_more_data = true;
          break;
        }

        /* Find crlf end and calculate crlf size */
        crlf_end = memspn(((const char*)databuffer.head())+crlf_start,"\r\n",5);
        crlf_size = (crlf_start + crlf_end) - crlf_start;

        /* Is this the end of a previous stream? (This is just before the boundary) */
        if ( crlf_start == 0 ) {
          databuffer.consume(crlf_size);
          continue;        
        }

        /* Check for invalid CRLF size */
        if ( crlf_size > 4 ) {
          Error("Invalid CRLF length");
        }

        /* Check if the crlf is \n\n or \r\n\r\n (marks end of headers, this is the last header) */
        if( (crlf_size == 2 && memcmp(((const char*)databuffer.head())+crlf_start,"\n\n",2) == 0) || (crlf_size == 4 && memcmp(((const char*)databuffer.head())+crlf_start,"\r\n\r\n",4) == 0) ) {
          /* This is the last header */
          SubHeadersParsingComplete = true;
        }

        /* Copy the subheader, excluding the crlf */
        subheader.assign(databuffer, crlf_start);

        /* Advance the buffer past this one */
        databuffer.consume(crlf_start+crlf_size);

        Debug(7,"Got subheader: %s",subheader.c_str());

        /* Find where the data in this header starts */
        size_t subheader_data_start = subheader.rfind(' ');
        if ( subheader_data_start == std::string::npos ) {
          subheader_data_start = subheader.find(':');
        }

        /* Extract the data into a string */
        std::string subheader_data = subheader.substr(subheader_data_start+1, std::string::npos);

        Debug(8,"Got subheader data: %s",subheader_data.c_str());

        /* Check the header */
        if(strncasecmp(subheader.c_str(),content_length_match,content_length_match_len) == 0) {  
          /* Found the content-length header */
          frame_content_length = atoi(subheader_data.c_str());
          Debug(6,"Got content-length subheader: %d",frame_content_length);
        } else if(strncasecmp(subheader.c_str(),content_type_match,content_type_match_len) == 0) { 
          /* Found the content-type header */
          frame_content_type = subheader_data;
          Debug(6,"Got content-type subheader: %s",frame_content_type.c_str());
        }

      }

      /* Attempt to extract the frame */
      if(!need_more_data) {
        if(!SubHeadersParsingComplete) {
          /* We haven't parsed all headers yet */
          need_more_data = true;
        } else if ( ! frame_content_length ) {
          /* Invalid frame */
          Error("Invalid frame: invalid content length");
        } else if ( frame_content_type != "image/jpeg" ) {
          /* Unsupported frame type */
          Error("Unsupported frame: %s",frame_content_type.c_str());
        } else if(frame_content_length > databuffer.size()) {
          /* Incomplete frame, wait for more data */
          need_more_data = true;
        } else {
          /* All good. decode the image */
          image.DecodeJpeg(databuffer.extract(frame_content_length), frame_content_length, colours, subpixelorder);
          frameComplete = true;
        }
      }

      /* Attempt to get more data */
      if(need_more_data) {
        nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex);
        if(nRet != 0) {
          Error("Failed waiting for available data condition variable: %s",strerror(nRet));
          return -18;
        }
        need_more_data = false;
      }

    } else if(mode == MODE_SINGLE) { 
      /* Check if we have anything */
      if (!single_offsets.empty()) {
        if( (single_offsets.front() > 0) && (databuffer.size() >= single_offsets.front()) ) {
          /* Extract frame */
          image.DecodeJpeg(databuffer.extract(single_offsets.front()), single_offsets.front(), colours, subpixelorder);
          single_offsets.pop_front();
          frameComplete = true;
        } else {
          /* This shouldn't happen */
          Error("Internal error. Attempting recovery");
          databuffer.consume(single_offsets.front());
          single_offsets.pop_front();
        }
      } else {
        /* Don't have a frame yet, wait for the request complete condition variable */
        nRet = pthread_cond_wait(&request_complete_cond,&shareddata_mutex);
        if(nRet != 0) {
          Error("Failed waiting for request complete condition variable: %s",strerror(nRet));
          return -19;
        }
      }
    } else {
      /* Failed to match content-type */
      Fatal("Unable to match Content-Type. Check URL, username and password");
    } /* mode */

  } /* frameComplete loop */

  /* Release the mutex */
  unlock();

  if(!frameComplete)
    return -1;

  return 1;
}
예제 #6
0
long parse_integer(char *str, char **endptr,
                   int len, int base, int *err){
  if(len == 0){
    len = strlen(str);
  }
  //since signed overflow is undefined and I don't really
  //want to use gmp for this, use an unsigned long to hold the value
  uint64_t num = 0;
  int i = 0, negitive = 0, overflow = 0;
  //ignore leading space
  while(isspace(str[i]) && ++i < len);
  if(i < len){
    if(str[i] == '-'){
      negitive = 1;
      i++;
    }
  }
  if(i == len){
    if(endptr){*endptr = str;}
    return 0;
  }
#define TO_NUMBER(start, end, base)                     \
  ({uint64_t number = 0, next = 0;                      \
    int j;                                              \
    for(j = start; j < end; j++){                       \
      next = (number * base) + char_to_number(str[j]);  \
      if(next < number){/*overflow*/                    \
        overflow = j;                                   \
        break;                                          \
      } else {                                          \
        number = next;                                  \
      }                                                 \
    }                                                   \
    number;})
//I'm pretty sure this will cause an error if the string is something like
//0x abcdefg. It should be read as a 0, but I'm not sure what will happen
  if(base == 0 && ((i+1) < len)){
    if(str[i] == '0' && str[i+1] == 'x'){
      base = 16;
      i+=2;
    } else if(str[i] == '0' && str[i+1] == 'o'){
      base = 8;
      i+=2;
    } else if(str[i] == '0' && str[i+1] == 'b'){
      base = 2;
      i+=2;
    } else {
      base = 10;
    }
  }
  while(str[i] == '0' && ++i < len);//read leading zeros
  if(i == len){
    if(endptr){*endptr = (str+i);}
    return 0;
  }
   /*
    Use special cases for 2, 8, 10, and 16 to speed them up.
    Multiplies in base 2, 8, or 16 become shifts, and for x86 at least
    a multiply by 10 becomes two lea instructions.
   */
#define DO_CASE(base)                                                   \
  if(i <= max_length_per_base[base]){                                   \
    num = TO_NUMBER(start, i, base);                                    \
  }                                                                     \
  if(i > max_length_per_base[base] || overflow > 0 || num>LONG_MAX){    \
    *err = errno = ERANGE;                                              \
    *endptr = (str+i);                                                  \
    return (negitive ? LONG_MIN : LONG_MAX);                            \
  }
  int start = i;
  if(base == 10){
    while(isdigit(str[i]) && ++i < len);
    DO_CASE(base);
  } else if(base == 16){
    while(isxdigit(str[i]) && ++i < len);
    DO_CASE(base);
  } else if(base == 8){
    while(is_oct_digit(str[i]) && ++i < len);
    DO_CASE(base);
  } else if(base == 2){
    while(is_binary_digit(str[i]) && ++i < len);
    DO_CASE(base);
  } else if(base < 10){
    i = memspn((uint8_t*)str + i, len - i, valid_digits, base);
    DO_CASE(base);
  } else {
    i = memspn((uint8_t*)str + i, len -i, valid_digits, 10 + (base-10)*2);
    DO_CASE(base);
  }
  if(endptr){*endptr = (str + i);}
  return (long)(negitive ? -num : num);
}