1
0

HTTPReader.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. #include "HTTPReader.h"
  2. #include "..\Components\wac_network\wac_network_http_receiver_api.h"
  3. #include "api__filereader.h"
  4. #include "../nu/AutoChar.h"
  5. #include <api/service/waservicefactory.h>
  6. #include <api/filereader/api_readercallback.h>
  7. #include <wchar.h>
  8. #include <bfc/platform/strcmp.h>
  9. #include <bfc/platform/minmax.h>
  10. #ifdef _WIN32
  11. #include <shlwapi.h>
  12. #endif
  13. #ifdef __APPLE__
  14. #include <unistd.h>
  15. #endif
  16. #include <stdexcept>
  17. // so we don't accidently call these CRT functions
  18. #ifdef close
  19. #undef close
  20. #endif
  21. #ifdef open
  22. #undef open
  23. #endif
  24. #ifdef read
  25. #undef read
  26. #endif
  27. #define config_guess_prebuffer true
  28. #define config_buffer_size 64
  29. #define config_prebuffer_size 24
  30. #define config_prebuffer_min 0
  31. #define config_allowseek true
  32. #define config_fullseek true
  33. #define config_seekprebuffer 1
  34. #define config_suppressstatus false
  35. // {C0A565DC-0CFE-405a-A27C-468B0C8A3A5C}
  36. static const GUID internetConfigGroupGUID =
  37. {
  38. 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c }
  39. };
  40. class HttpReader
  41. {
  42. public:
  43. HttpReader(const char *url, uint64_t start_offset = 0, uint64_t total_len = 0, int is_seek = 0);
  44. ~HttpReader();
  45. int connect();
  46. int read(int8_t *buffer, int length);
  47. void abort() { killswitch = 1; }
  48. int bytesAvailable();
  49. uint64_t getContentLength()
  50. {
  51. if (m_contentlength)
  52. return m_contentlength;
  53. return -1;
  54. }
  55. int canSeek()
  56. {
  57. return (m_contentlength &&
  58. /* JF> this is correct but not as compatible: m_accept_ranges && */
  59. !m_meta_interval);
  60. }
  61. uint64_t getPos() { return m_contentpos; }
  62. const char *getHeader( const char *header ) { return httpGetter->getheader( (char *)header ); }
  63. void setMetaCB( api_readercallback *cb ) { metacb = cb; }
  64. //static BOOL CALLBACK httpDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  65. private:
  66. api_httpreceiver *httpGetter = NULL;
  67. api_dns *dns = NULL;
  68. char *m_AllHeaders;
  69. int buffer_size;
  70. int prebuffer_size, prebuffer_min;
  71. int need_prebuffer;
  72. uint64_t m_contentlength, m_contentpos;
  73. int m_accept_ranges;
  74. int proxy_enabled;
  75. char *proxy;
  76. int killswitch = -1;
  77. int m_meta_init, m_meta_interval, m_meta_pos, m_meta_size, m_meta_buf_pos;
  78. char m_meta_buf[4096];
  79. api_readercallback *metacb;
  80. int guessed_prebuffer_size;
  81. char lpinfo[256];
  82. char force_lpinfo[256];
  83. char *dlg_realm;
  84. char *m_url;
  85. };
  86. HttpReader::HttpReader( const char *url, uint64_t start_offset, uint64_t total_len, int is_seek )
  87. {
  88. m_accept_ranges = 0;
  89. buffer_size = (config_buffer_size * 1024);
  90. prebuffer_size = (config_prebuffer_size * 1024);
  91. prebuffer_min = (config_prebuffer_min * 1024);
  92. guessed_prebuffer_size = !config_guess_prebuffer;
  93. if (is_seek)
  94. {
  95. prebuffer_min = prebuffer_size = config_seekprebuffer;
  96. guessed_prebuffer_size = 1;
  97. }
  98. proxy_enabled = 0;
  99. killswitch = 0;
  100. need_prebuffer = 0;
  101. m_contentlength = total_len;
  102. m_contentpos = start_offset;
  103. m_meta_init = m_meta_interval = m_meta_pos = m_meta_size = m_meta_buf_pos = 0;
  104. m_meta_buf[0] = 0;
  105. metacb = NULL;
  106. force_lpinfo[0] = 0;
  107. lpinfo[0] = 0;
  108. m_url = _strdup(url);
  109. int use_proxy = 1;
  110. bool proxy80 = AGAVE_API_CONFIG->GetBool(internetConfigGroupGUID, L"proxy80", false);
  111. if (proxy80 && strstr(url, ":") && (!strstr(url, ":80/") && strstr(url, ":80") != (url + strlen(url) - 3)))
  112. use_proxy = 0;
  113. waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid( httpreceiverGUID );
  114. if (sf)
  115. httpGetter = (api_httpreceiver *)sf->getInterface();
  116. const wchar_t *proxy = AGAVE_API_CONFIG->GetString(internetConfigGroupGUID, L"proxy", 0);
  117. httpGetter->open(API_DNS_AUTODNS, buffer_size, (use_proxy && proxy && proxy[0]) ? (char *)AutoChar(proxy) : NULL);
  118. httpGetter->addheader("Accept:*/*");
  119. if (!_strnicmp(url, "uvox://", 7))
  120. {
  121. httpGetter->addheader("User-Agent: ultravox/2.0");
  122. }
  123. else
  124. {
  125. httpGetter->AddHeaderValue("User-Agent", AutoChar(WASABI_API_APP->main_getVersionString()));
  126. }
  127. if (start_offset > 0)
  128. {
  129. char temp[128];
  130. sprintf(temp, "Range: bytes=%d-", (int)start_offset);
  131. httpGetter->addheader(temp);
  132. }
  133. else
  134. httpGetter->addheader("Icy-Metadata:1");
  135. httpGetter->connect((char *)m_url, start_offset > 0);
  136. HttpReader::connect();
  137. HttpReader::read(0, 0);
  138. //if (!config_suppressstatus) api->core_setCustomMsg(0, StringPrintf("[Connecting] %s",url));
  139. }
  140. HttpReader::~HttpReader()
  141. {
  142. waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid( httpreceiverGUID );
  143. if ( sf )
  144. sf->releaseInterface( httpGetter );
  145. }
  146. // TODO: BOOL CALLBACK HttpReader::httpDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
  147. int HttpReader::connect()
  148. {
  149. try
  150. {
  151. while ( killswitch >= 0 && httpGetter->run() == 0 && httpGetter->get_status() == 0 )
  152. {
  153. #ifdef _WIN32
  154. //Sleep( 50 );
  155. #else
  156. usleep( 50000 );
  157. #endif
  158. }
  159. if ( killswitch )
  160. return 0;
  161. if ( httpGetter->get_status() == -1 )
  162. {
  163. int code = httpGetter->getreplycode();
  164. if ( code == 401 )
  165. {
  166. /* TODO:
  167. // authorization required
  168. JNL_Connection *m_connection=httpGetter->get_con();
  169. char str[4096];
  170. while (m_connection->recv_lines_available() > 0) {
  171. char *wwwa="WWW-Authenticate:";
  172. m_connection->recv_line(str,4096);
  173. if (!str[0]) break;
  174. if (!_strnicmp(str,wwwa,strlen(wwwa))) {
  175. char *s2="Basic realm=\"";
  176. char *p=str+strlen(wwwa); while (p && *p== ' ') p++;
  177. if (!_strnicmp(p,s2,strlen(s2))) {
  178. p+=strlen(s2);
  179. if (strstr(p,"\"")) {
  180. strstr(p,"\"")[0]=0;
  181. if (*p) {
  182. if(force_lpinfo[0]) {
  183. force_lpinfo[0]=0; // invalid l/p
  184. } else WASABI_API_CONFIG->getStringPrivate(StringPrintf("HTTP-AUTH/%s",p),force_lpinfo,sizeof(force_lpinfo),"");
  185. if (!force_lpinfo[0] || lpinfo[0]) {
  186. dlg_realm = p;
  187. api->pushModalWnd();
  188. RootWnd *pr=api->main_getRootWnd();
  189. while(pr->getParent()) pr=pr->getParent();
  190. if (!DialogBoxParam(the->gethInstance(),MAKEINTRESOURCE(IDD_HTTPAUTH),pr->gethWnd(),httpDlgProc,(long)this)) {
  191. force_lpinfo[0]=0;
  192. } else {
  193. WASABI_API_CONFIG->setStringPrivate(StringPrintf("HTTP-AUTH/%s",p),force_lpinfo);
  194. }
  195. api->popModalWnd();
  196. }
  197. if (force_lpinfo[0]) {
  198. const char *p=STRSTR(m_url,"http://");
  199. if(p) {
  200. p+=7;
  201. StringPrintf tmp("http://%s@%s",force_lpinfo,p);
  202. httpGetter->connect((char *)tmp.getValue());
  203. return connect(); // recursive city
  204. }
  205. }
  206. }
  207. }
  208. }
  209. break;
  210. }
  211. }*/
  212. }
  213. // TODO: api->core_setCustomMsg(0, StringPrintf("HTTP: can't connect (%i)",code));
  214. return 0;
  215. }
  216. if ( httpGetter->getreplycode() < 200 || httpGetter->getreplycode() > 299 )
  217. {
  218. // TODO: api->core_setCustomMsg(0, StringPrintf("HTTP: returned %i",httpGetter->getreplycode()));
  219. return 0;
  220. }
  221. need_prebuffer = 1;
  222. }
  223. catch ( const std::exception &e )
  224. {
  225. return 0;
  226. }
  227. return 1;
  228. }
  229. int HttpReader::bytesAvailable()
  230. {
  231. int code = httpGetter->run();
  232. int ba = httpGetter->bytes_available();
  233. if ( !ba && code )
  234. return -1;
  235. return ba;
  236. }
  237. int HttpReader::read(int8_t *buffer, int length)
  238. {
  239. if (!httpGetter->GetConnection())
  240. return 0;
  241. if ( httpGetter->GetConnection()->get_state() == CONNECTION_STATE_CONNECTED && httpGetter->bytes_available() < prebuffer_min )
  242. need_prebuffer = 1;
  243. if (need_prebuffer)
  244. {
  245. need_prebuffer = 0;
  246. // TODO: if (!config_suppressstatus) api->core_setCustomMsg(0, "Prebuffering ...");
  247. if (!guessed_prebuffer_size)
  248. {
  249. // wait for headers
  250. int s;
  251. do
  252. {
  253. s = httpGetter->run();
  254. }
  255. while (s == 0 && httpGetter->get_status() != 2);
  256. // calculate the needed prebuffer size if it's a shoutcast stream
  257. const char *icybr;
  258. if (icybr = httpGetter->getheader("icy-br"))
  259. {
  260. prebuffer_size = (atoi(icybr) / 8) * 4096;
  261. prebuffer_min = (atoi(icybr) / 8) * 1024;
  262. if (prebuffer_size > buffer_size)
  263. prebuffer_size = buffer_size;
  264. }
  265. guessed_prebuffer_size = 1;
  266. }
  267. int last_pre = -1;
  268. while (httpGetter->bytes_available() < prebuffer_size && !killswitch)
  269. {
  270. int s = httpGetter->run();
  271. // JNL_Connection::state s = getter->get_state();
  272. // if (s == JNL_Connection::STATE_ERROR || s == JNL_Connection::STATE_CLOSED) break;
  273. if (s == -1 || s == 1) break;
  274. #ifdef _WIN32
  275. Sleep(50);
  276. #else
  277. usleep(50000);
  278. #endif
  279. if (last_pre != httpGetter->bytes_available() && !killswitch)
  280. {
  281. // TODO: if (!config_suppressstatus) api->core_setCustomMsg(0, StringPrintf(0, "Prebuffering : %i/%i bytes",httpGetter->bytes_available(),prebuffer_size));
  282. }
  283. }
  284. // if (!killswitch)
  285. // {
  286. //// TODO: if (!config_suppressstatus) api->core_setCustomMsg(0, "Prebuffering done.");
  287. // }
  288. }
  289. if (killswitch) return 0;
  290. // metadata filtering
  291. if ( !m_meta_init )
  292. {
  293. const char *v;
  294. if ( v = httpGetter->getheader( "icy-metaint:" ) )
  295. m_meta_interval = atoi( v );
  296. if ( !m_contentlength )
  297. {
  298. if ( v = httpGetter->getheader( "content-length:" ) )
  299. m_contentlength = _strtoui64( v, NULL, 10 );//atoi(v);
  300. }
  301. v = httpGetter->getheader( "accept-ranges:" );
  302. if ( v && strcasestr( v, "bytes" ) )
  303. m_accept_ranges = 1;
  304. m_meta_init = 1;
  305. }
  306. int error = 0, recvBytes = 0;
  307. while (length && !error && !killswitch)
  308. {
  309. int code = httpGetter->run();
  310. if (code != 0)
  311. error = 1;
  312. // old metadata parsing
  313. /*if (httpGetter->bytes_available()>0) {
  314. int l=httpGetter->get_bytes(buffer,length);
  315. // metadata stuff
  316. if (m_meta_interval) {
  317. int x=l;
  318. unsigned char *buf=(unsigned char *)buffer;
  319. if (m_meta_size)// already in meta block
  320. {
  321. int len=MIN(x,m_meta_size-m_meta_buf_pos);
  322. MEMCPY(m_meta_buf+m_meta_buf_pos,buf,len);
  323. m_meta_buf_pos+=len;
  324. if (m_meta_buf_pos==m_meta_size)
  325. {
  326. if(metacb) metacb->metaDataReader_onData(m_meta_buf,m_meta_size);
  327. m_meta_buf_pos=0;
  328. m_meta_size=0;
  329. m_meta_pos=0;
  330. }
  331. x-=len;
  332. if (x) MEMCPY(buf,buf+len,x);
  333. }
  334. else if (m_meta_pos+x > m_meta_interval) // block contains meta data somewhere in it, and we're not alreayd reading a block
  335. {
  336. int start_offs=m_meta_interval-m_meta_pos;
  337. int len;
  338. m_meta_size=((unsigned char *)buf)[start_offs]*16;
  339. len=MIN(x-start_offs-1,m_meta_size);
  340. if (len) MEMCPY(m_meta_buf,buf+start_offs+1,len);
  341. m_meta_buf_pos=len;
  342. if (m_meta_buf_pos==m_meta_size) // full read of metadata successful
  343. {
  344. x-=m_meta_size+1;
  345. if (x > start_offs) MEMCPY(buf+start_offs,buf+start_offs+1+m_meta_size,x-start_offs);
  346. if(metacb) metacb->metaDataReader_onData(m_meta_buf,m_meta_size);
  347. m_meta_buf_pos=0;
  348. m_meta_pos=-start_offs;
  349. m_meta_size=0;
  350. }
  351. else
  352. {
  353. x=start_offs; // otherwise, there's only the first block of data
  354. }
  355. }
  356. if (x > 0)
  357. {
  358. m_meta_pos+=x;
  359. }
  360. l=x;
  361. }
  362. length-=l;
  363. buffer+=l;
  364. recvBytes+=l;
  365. } else Sleep(50);*/
  366. while (1)
  367. {
  368. int len = httpGetter->bytes_available();
  369. if (m_meta_interval && m_meta_pos >= m_meta_interval)
  370. {
  371. unsigned char b;
  372. if (len > 0 && httpGetter->peek_bytes((char*)&b, 1) && len > (b << 4))
  373. {
  374. char metabuf[4096];
  375. httpGetter->get_bytes(metabuf, 1);
  376. httpGetter->get_bytes(metabuf, b << 4);
  377. if (metacb) metacb->metaDataReader_onData(metabuf, b << 4);
  378. //stream_metabytes_read+=(b<<4)+1;
  379. m_meta_pos = 0;
  380. }
  381. else
  382. break;
  383. }
  384. else
  385. {
  386. len = MIN(length, len);
  387. if (m_meta_interval)
  388. len = MIN(m_meta_interval - m_meta_pos, len);
  389. if (len > 0)
  390. {
  391. len = httpGetter->get_bytes((char*)buffer, len);
  392. m_meta_pos += len;
  393. //stream_bytes_read+=len;
  394. length -= len;
  395. buffer += len;
  396. recvBytes += len;
  397. }
  398. else
  399. {
  400. #ifdef _WIN32
  401. Sleep(50);
  402. #else
  403. usleep(50000);
  404. #endif
  405. }
  406. break;
  407. }
  408. }
  409. /* int s=httpGetter->get_con()->get_state();
  410. if(code==0) {*/
  411. /* char tmp[512];
  412. wsprintf(tmp,"[Connected] Retrieving list (%i bytes)", recvBytes);
  413. api->status_setText(tmp);*/
  414. // } else error=1;
  415. }
  416. m_contentpos += recvBytes;
  417. return recvBytes;
  418. }
  419. /* ---------------------------------------------------------------------- */
  420. int HTTPReader::isMine(const wchar_t *filename, int mode)
  421. {
  422. if (!_wcsnicmp(filename, L"http://", 7) ||
  423. !_wcsnicmp(filename, L"https://", 8) ||
  424. !_wcsnicmp(filename, L"icy://", 6) ||
  425. !_wcsnicmp(filename, L"sc://", 5) ||
  426. !_wcsnicmp(filename, L"uvox://", 7)) return 1;
  427. return 0;
  428. }
  429. int HTTPReader::open( const wchar_t *filename, int mode )
  430. {
  431. if ( !isMine( filename, mode ) )
  432. return 0;
  433. m_filename = _strdup( AutoChar( filename ) );
  434. reader = new HttpReader( m_filename );
  435. return 1;
  436. }
  437. uint64_t HTTPReader::bytesAvailable( uint64_t requested )
  438. {
  439. int v = reader ? reader->bytesAvailable() : 0;
  440. if ( v > requested )
  441. return requested;
  442. return v;
  443. }
  444. size_t HTTPReader::read( int8_t *buffer, size_t length )
  445. {
  446. if ( !reader )
  447. return 0;
  448. if ( !hasConnected )
  449. {
  450. int res = reader->connect();
  451. if ( !res )
  452. return 0;
  453. hasConnected = 1;
  454. }
  455. return reader->read( buffer, (int)length );
  456. }
  457. void HTTPReader::close()
  458. {
  459. delete reader;
  460. reader = NULL;
  461. }
  462. void HTTPReader::abort()
  463. {
  464. if ( reader )
  465. reader->abort();
  466. }
  467. uint64_t HTTPReader::getLength()
  468. {
  469. return reader ? reader->getContentLength() : -1;
  470. }
  471. uint64_t HTTPReader::getPos()
  472. {
  473. return reader ? reader->getPos() : 0;
  474. }
  475. int HTTPReader::canSeek()
  476. {
  477. return ( config_allowseek && reader && reader->canSeek() ) ? ( config_fullseek ? 1 : -1 ) : 0;
  478. }
  479. int HTTPReader::seek( uint64_t position )
  480. {
  481. if ( reader && reader->canSeek() && config_allowseek )
  482. {
  483. if ( position == getPos() ) return 0;
  484. hasConnected = 0;
  485. uint64_t cl = reader->getContentLength();
  486. delete( (HttpReader *)reader );
  487. reader = new HttpReader( m_filename, position, cl, 1 );
  488. return 0;
  489. }
  490. return -1;
  491. }
  492. int HTTPReader::hasHeaders()
  493. {
  494. return 1;
  495. }
  496. const char *HTTPReader::getHeader( const char *header )
  497. {
  498. return reader ? reader->getHeader( header ) : NULL;
  499. }
  500. void HTTPReader::setMetaDataCallback( api_readercallback *cb )
  501. {
  502. if ( reader )
  503. reader->setMetaCB( cb );
  504. }
  505. #define CBCLASS HTTPReader
  506. START_DISPATCH;
  507. CB(ISMINE, isMine);
  508. CB(OPEN, open);
  509. CB(READ, read);
  510. CB(WRITE, write);
  511. VCB(CLOSE, close);
  512. VCB(ABORT, abort);
  513. CB(GETLENGTH, getLength);
  514. CB(GETPOS, getPos);
  515. CB(CANSEEK, canSeek);
  516. CB(SEEK, seek);
  517. CB(HASHEADERS, hasHeaders);
  518. CB(GETHEADER, getHeader);
  519. CB(EXISTS, exists);
  520. // CB(REMOVE,remove);
  521. // CB(REMOVEUNDOABLE,removeUndoable);
  522. // CB(MOVE,move);
  523. CB(BYTESAVAILABLE, bytesAvailable);
  524. VCB(SETMETADATACALLBACK, setMetaDataCallback);
  525. CB(CANPREFETCH, canPrefetch);
  526. // CB(CANSETEOF, canSetEOF);
  527. // CB(SETEOF, setEOF);
  528. END_DISPATCH;
  529. #undef CBCLASS