123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630 |
- #include "HTTPReader.h"
- #include "..\Components\wac_network\wac_network_http_receiver_api.h"
- #include "api__filereader.h"
- #include "../nu/AutoChar.h"
- #include <api/service/waservicefactory.h>
- #include <api/filereader/api_readercallback.h>
- #include <wchar.h>
- #include <bfc/platform/strcmp.h>
- #include <bfc/platform/minmax.h>
- #ifdef _WIN32
- #include <shlwapi.h>
- #endif
- #ifdef __APPLE__
- #include <unistd.h>
- #endif
- #include <stdexcept>
- #ifdef close
- #undef close
- #endif
- #ifdef open
- #undef open
- #endif
- #ifdef read
- #undef read
- #endif
- #define config_guess_prebuffer true
- #define config_buffer_size 64
- #define config_prebuffer_size 24
- #define config_prebuffer_min 0
- #define config_allowseek true
- #define config_fullseek true
- #define config_seekprebuffer 1
- #define config_suppressstatus false
- static const GUID internetConfigGroupGUID =
- {
- 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c }
- };
- class HttpReader
- {
- public:
- HttpReader(const char *url, uint64_t start_offset = 0, uint64_t total_len = 0, int is_seek = 0);
- ~HttpReader();
- int connect();
- int read(int8_t *buffer, int length);
-
- void abort() { killswitch = 1; }
-
- int bytesAvailable();
- uint64_t getContentLength()
- {
- if (m_contentlength)
- return m_contentlength;
- return -1;
- }
- int canSeek()
- {
- return (m_contentlength &&
-
- !m_meta_interval);
- }
- uint64_t getPos() { return m_contentpos; }
- const char *getHeader( const char *header ) { return httpGetter->getheader( (char *)header ); }
- void setMetaCB( api_readercallback *cb ) { metacb = cb; }
-
- private:
- api_httpreceiver *httpGetter = NULL;
- api_dns *dns = NULL;
- char *m_AllHeaders;
- int buffer_size;
- int prebuffer_size, prebuffer_min;
- int need_prebuffer;
- uint64_t m_contentlength, m_contentpos;
- int m_accept_ranges;
- int proxy_enabled;
- char *proxy;
- int killswitch = -1;
- int m_meta_init, m_meta_interval, m_meta_pos, m_meta_size, m_meta_buf_pos;
- char m_meta_buf[4096];
- api_readercallback *metacb;
- int guessed_prebuffer_size;
- char lpinfo[256];
- char force_lpinfo[256];
- char *dlg_realm;
- char *m_url;
- };
- HttpReader::HttpReader( const char *url, uint64_t start_offset, uint64_t total_len, int is_seek )
- {
- m_accept_ranges = 0;
- buffer_size = (config_buffer_size * 1024);
- prebuffer_size = (config_prebuffer_size * 1024);
- prebuffer_min = (config_prebuffer_min * 1024);
- guessed_prebuffer_size = !config_guess_prebuffer;
- if (is_seek)
- {
- prebuffer_min = prebuffer_size = config_seekprebuffer;
- guessed_prebuffer_size = 1;
- }
- proxy_enabled = 0;
- killswitch = 0;
- need_prebuffer = 0;
- m_contentlength = total_len;
- m_contentpos = start_offset;
- m_meta_init = m_meta_interval = m_meta_pos = m_meta_size = m_meta_buf_pos = 0;
- m_meta_buf[0] = 0;
- metacb = NULL;
- force_lpinfo[0] = 0;
- lpinfo[0] = 0;
- m_url = _strdup(url);
- int use_proxy = 1;
- bool proxy80 = AGAVE_API_CONFIG->GetBool(internetConfigGroupGUID, L"proxy80", false);
- if (proxy80 && strstr(url, ":") && (!strstr(url, ":80/") && strstr(url, ":80") != (url + strlen(url) - 3)))
- use_proxy = 0;
- waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid( httpreceiverGUID );
- if (sf)
- httpGetter = (api_httpreceiver *)sf->getInterface();
- const wchar_t *proxy = AGAVE_API_CONFIG->GetString(internetConfigGroupGUID, L"proxy", 0);
- httpGetter->open(API_DNS_AUTODNS, buffer_size, (use_proxy && proxy && proxy[0]) ? (char *)AutoChar(proxy) : NULL);
- httpGetter->addheader("Accept:*/*");
- if (!_strnicmp(url, "uvox://", 7))
- {
- httpGetter->addheader("User-Agent: ultravox/2.0");
- }
- else
- {
- httpGetter->AddHeaderValue("User-Agent", AutoChar(WASABI_API_APP->main_getVersionString()));
- }
- if (start_offset > 0)
- {
- char temp[128];
- sprintf(temp, "Range: bytes=%d-", (int)start_offset);
- httpGetter->addheader(temp);
- }
- else
- httpGetter->addheader("Icy-Metadata:1");
- httpGetter->connect((char *)m_url, start_offset > 0);
- HttpReader::connect();
- HttpReader::read(0, 0);
-
- }
- HttpReader::~HttpReader()
- {
- waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid( httpreceiverGUID );
- if ( sf )
- sf->releaseInterface( httpGetter );
- }
- int HttpReader::connect()
- {
- try
- {
- while ( killswitch >= 0 && httpGetter->run() == 0 && httpGetter->get_status() == 0 )
- {
- #ifdef _WIN32
-
- #else
- usleep( 50000 );
- #endif
- }
- if ( killswitch )
- return 0;
- if ( httpGetter->get_status() == -1 )
- {
- int code = httpGetter->getreplycode();
- if ( code == 401 )
- {
-
- }
-
- return 0;
- }
- if ( httpGetter->getreplycode() < 200 || httpGetter->getreplycode() > 299 )
- {
-
- return 0;
- }
- need_prebuffer = 1;
- }
- catch ( const std::exception &e )
- {
- return 0;
- }
- return 1;
- }
- int HttpReader::bytesAvailable()
- {
- int code = httpGetter->run();
- int ba = httpGetter->bytes_available();
- if ( !ba && code )
- return -1;
- return ba;
- }
- int HttpReader::read(int8_t *buffer, int length)
- {
- if (!httpGetter->GetConnection())
- return 0;
- if ( httpGetter->GetConnection()->get_state() == CONNECTION_STATE_CONNECTED && httpGetter->bytes_available() < prebuffer_min )
- need_prebuffer = 1;
- if (need_prebuffer)
- {
- need_prebuffer = 0;
-
- if (!guessed_prebuffer_size)
- {
-
- int s;
- do
- {
- s = httpGetter->run();
- }
- while (s == 0 && httpGetter->get_status() != 2);
-
- const char *icybr;
- if (icybr = httpGetter->getheader("icy-br"))
- {
- prebuffer_size = (atoi(icybr) / 8) * 4096;
- prebuffer_min = (atoi(icybr) / 8) * 1024;
- if (prebuffer_size > buffer_size)
- prebuffer_size = buffer_size;
- }
- guessed_prebuffer_size = 1;
- }
- int last_pre = -1;
- while (httpGetter->bytes_available() < prebuffer_size && !killswitch)
- {
- int s = httpGetter->run();
-
- if (s == -1 || s == 1) break;
- #ifdef _WIN32
- Sleep(50);
- #else
- usleep(50000);
- #endif
- if (last_pre != httpGetter->bytes_available() && !killswitch)
- {
- }
- }
- }
- if (killswitch) return 0;
-
- if ( !m_meta_init )
- {
- const char *v;
- if ( v = httpGetter->getheader( "icy-metaint:" ) )
- m_meta_interval = atoi( v );
- if ( !m_contentlength )
- {
- if ( v = httpGetter->getheader( "content-length:" ) )
- m_contentlength = _strtoui64( v, NULL, 10 );
- }
- v = httpGetter->getheader( "accept-ranges:" );
- if ( v && strcasestr( v, "bytes" ) )
- m_accept_ranges = 1;
- m_meta_init = 1;
- }
- int error = 0, recvBytes = 0;
- while (length && !error && !killswitch)
- {
- int code = httpGetter->run();
- if (code != 0)
- error = 1;
-
-
- while (1)
- {
- int len = httpGetter->bytes_available();
- if (m_meta_interval && m_meta_pos >= m_meta_interval)
- {
- unsigned char b;
- if (len > 0 && httpGetter->peek_bytes((char*)&b, 1) && len > (b << 4))
- {
- char metabuf[4096];
- httpGetter->get_bytes(metabuf, 1);
- httpGetter->get_bytes(metabuf, b << 4);
- if (metacb) metacb->metaDataReader_onData(metabuf, b << 4);
-
- m_meta_pos = 0;
- }
- else
- break;
- }
- else
- {
- len = MIN(length, len);
- if (m_meta_interval)
- len = MIN(m_meta_interval - m_meta_pos, len);
- if (len > 0)
- {
- len = httpGetter->get_bytes((char*)buffer, len);
- m_meta_pos += len;
-
- length -= len;
- buffer += len;
- recvBytes += len;
- }
- else
- {
- #ifdef _WIN32
- Sleep(50);
- #else
- usleep(50000);
- #endif
- }
- break;
- }
- }
-
-
- }
- m_contentpos += recvBytes;
-
- return recvBytes;
- }
- int HTTPReader::isMine(const wchar_t *filename, int mode)
- {
- if (!_wcsnicmp(filename, L"http://", 7) ||
- !_wcsnicmp(filename, L"https://", 8) ||
- !_wcsnicmp(filename, L"icy://", 6) ||
- !_wcsnicmp(filename, L"sc://", 5) ||
- !_wcsnicmp(filename, L"uvox://", 7)) return 1;
- return 0;
- }
- int HTTPReader::open( const wchar_t *filename, int mode )
- {
- if ( !isMine( filename, mode ) )
- return 0;
- m_filename = _strdup( AutoChar( filename ) );
- reader = new HttpReader( m_filename );
- return 1;
- }
- uint64_t HTTPReader::bytesAvailable( uint64_t requested )
- {
- int v = reader ? reader->bytesAvailable() : 0;
- if ( v > requested )
- return requested;
- return v;
- }
- size_t HTTPReader::read( int8_t *buffer, size_t length )
- {
- if ( !reader )
- return 0;
- if ( !hasConnected )
- {
- int res = reader->connect();
- if ( !res )
- return 0;
- hasConnected = 1;
- }
- return reader->read( buffer, (int)length );
- }
- void HTTPReader::close()
- {
- delete reader;
- reader = NULL;
- }
- void HTTPReader::abort()
- {
- if ( reader )
- reader->abort();
- }
- uint64_t HTTPReader::getLength()
- {
- return reader ? reader->getContentLength() : -1;
- }
- uint64_t HTTPReader::getPos()
- {
- return reader ? reader->getPos() : 0;
- }
- int HTTPReader::canSeek()
- {
- return ( config_allowseek && reader && reader->canSeek() ) ? ( config_fullseek ? 1 : -1 ) : 0;
- }
- int HTTPReader::seek( uint64_t position )
- {
- if ( reader && reader->canSeek() && config_allowseek )
- {
- if ( position == getPos() ) return 0;
- hasConnected = 0;
- uint64_t cl = reader->getContentLength();
- delete( (HttpReader *)reader );
- reader = new HttpReader( m_filename, position, cl, 1 );
- return 0;
- }
- return -1;
- }
- int HTTPReader::hasHeaders()
- {
- return 1;
- }
- const char *HTTPReader::getHeader( const char *header )
- {
- return reader ? reader->getHeader( header ) : NULL;
- }
- void HTTPReader::setMetaDataCallback( api_readercallback *cb )
- {
- if ( reader )
- reader->setMetaCB( cb );
- }
- #define CBCLASS HTTPReader
- START_DISPATCH;
- CB(ISMINE, isMine);
- CB(OPEN, open);
- CB(READ, read);
- CB(WRITE, write);
- VCB(CLOSE, close);
- VCB(ABORT, abort);
- CB(GETLENGTH, getLength);
- CB(GETPOS, getPos);
- CB(CANSEEK, canSeek);
- CB(SEEK, seek);
- CB(HASHEADERS, hasHeaders);
- CB(GETHEADER, getHeader);
- CB(EXISTS, exists);
- CB(BYTESAVAILABLE, bytesAvailable);
- VCB(SETMETADATACALLBACK, setMetaDataCallback);
- CB(CANPREFETCH, canPrefetch);
- END_DISPATCH;
- #undef CBCLASS
|