Opera 12.15 Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

statusxmldownloader.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. /* -*- Mode: c++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
  2. *
  3. * Copyright (C) 1995-2011 Opera Software AS. All rights reserved.
  4. *
  5. * This file is part of the Opera web browser. It may not be distributed
  6. * under any circumstances.
  7. *
  8. * @author Marius Blomli, Michal Zajaczkowski
  9. */
  10. #include "core/pch.h"
  11. #ifdef AUTO_UPDATE_SUPPORT
  12. #include "adjunct/autoupdate/statusxmldownloader.h"
  13. #include "adjunct/autoupdate/updatablefile.h"
  14. #include "adjunct/autoupdate/updatablesetting.h"
  15. #include "modules/prefs/prefsmanager/collections/pc_ui.h"
  16. #include "modules/xmlutils/xmlnames.h"
  17. #include "modules/url/url2.h"
  18. #include "modules/url/url_man.h"
  19. #include "modules/upload/upload.h"
  20. #include "modules/util/adt/bytebuffer.h"
  21. #ifdef _DEBUG
  22. #include "modules/dochand/win.h"
  23. #include "modules/dochand/winman.h"
  24. #endif
  25. #include "modules/util/opguid.h"
  26. #define AUTOUPDATE_XML_VERSION UNI_L("1.0")
  27. #define AUTOUPDATE_RESPONSE_FILE_NAME UNI_L("autoupdate_response.xml")
  28. OpVector<StatusXMLDownloader> StatusXMLDownloaderHolder::downloader_list;
  29. OP_STATUS StatusXMLDownloaderHolder::AddDownloader(StatusXMLDownloader* downloader)
  30. {
  31. OP_ASSERT(downloader);
  32. return downloader_list.Add(downloader);
  33. }
  34. OP_STATUS StatusXMLDownloaderHolder::RemoveDownloader(StatusXMLDownloader* downloader)
  35. {
  36. OP_ASSERT(downloader);
  37. return downloader_list.RemoveByItem(downloader);
  38. }
  39. void StatusXMLDownloaderHolder::ReplaceRedirectedFileURLs(const OpString& url, const OpString redirected_url)
  40. {
  41. for (UINT32 i=0; i<downloader_list.GetCount(); i++)
  42. {
  43. StatusXMLDownloader* downloader = downloader_list.Get(i);
  44. OP_ASSERT(downloader);
  45. OpStatus::Ignore(downloader->ReplaceRedirectedFileURL(url, redirected_url));
  46. }
  47. }
  48. ////////////////////////////////////////////////////////////////////////////////////////////////
  49. OP_STATUS StatusXMLDownloader::Init(CheckType check_type, StatusXMLDownloaderListener* listener)
  50. {
  51. OP_ASSERT(listener);
  52. OP_ASSERT(check_type != CheckTypeInvalid);
  53. m_listener = listener;
  54. m_check_type = check_type;
  55. RETURN_IF_ERROR(GenerateResponseFilename());
  56. RETURN_IF_ERROR(StatusXMLDownloaderHolder::AddDownloader(this));
  57. return OpStatus::OK;
  58. }
  59. OP_STATUS StatusXMLDownloader::GenerateResponseFilename()
  60. {
  61. switch (m_check_type)
  62. {
  63. case (CheckTypeUpdate):
  64. {
  65. m_response_file_folder = OPFILE_HOME_FOLDER;
  66. return m_response_file_name.Set(AUTOUPDATE_RESPONSE_FILE_NAME);
  67. }
  68. case (CheckTypeOther):
  69. {
  70. m_response_file_folder = OPFILE_TEMP_FOLDER;
  71. OpGuid guid;
  72. OpString8 temp;
  73. // GUID(37) + ".xml\0" */
  74. RETURN_OOM_IF_NULL(temp.Reserve(42));
  75. RETURN_IF_ERROR(g_opguidManager->GenerateGuid(guid));
  76. OpGUIDManager::ToString(guid, temp.DataPtr(), temp.Capacity());
  77. RETURN_IF_ERROR(temp.Append(".xml"));
  78. return m_response_file_name.Set(temp);
  79. }
  80. default:
  81. {
  82. OP_ASSERT(!"Unknown check type!");
  83. return OpStatus::ERR;
  84. }
  85. }
  86. }
  87. OP_STATUS StatusXMLDownloader::DeleteResponseFile()
  88. {
  89. #ifdef _DEBUG
  90. if(g_pcui->GetIntegerPref(PrefsCollectionUI::SaveAutoUpdateXML))
  91. return OpStatus::OK;
  92. #endif // _DEBUG
  93. // Don't delete the autoupdate_response.xml file since it might come in handy when it comes to reparsing the
  94. // resposne XML after a crash.
  95. if (CheckTypeUpdate == m_check_type)
  96. return OpStatus::OK;
  97. OP_ASSERT(m_response_file_name.HasContent());
  98. OpFile response_file;
  99. RETURN_IF_ERROR(response_file.Construct(m_response_file_name, m_response_file_folder));
  100. RETURN_IF_ERROR(response_file.Delete(FALSE));
  101. return OpStatus::OK;
  102. }
  103. StatusXMLDownloader::DownloadStatus StatusXMLDownloader::ParseDownloadedXML()
  104. {
  105. OP_ASSERT(m_response_file_name.HasContent());
  106. OpFile file;
  107. if (OpStatus::IsError(file.Construct(m_response_file_name.CStr(), m_response_file_folder)))
  108. return OUT_OF_MEMORY;
  109. if (OpStatus::IsError(file.Open(OPFILE_READ)))
  110. return LOAD_FAILED;
  111. // Define some element names for later use.
  112. const XMLCompleteName versioncheck_elm(UNI_L("urn:OperaAutoupdate"), UNI_L("oau"), UNI_L("versioncheck"));
  113. const XMLExpandedName file_elm(UNI_L("file"));
  114. const XMLExpandedName setting_elm(UNI_L("setting"));
  115. const XMLExpandedName version_att(UNI_L("version"));
  116. const XMLExpandedName resources_elm(UNI_L("resources"));
  117. // Parse downloaded xml.
  118. XMLFragment fragment;
  119. if (OpStatus::IsError(fragment.Parse(&file)))
  120. {
  121. file.Close();
  122. return PARSE_ERROR;
  123. }
  124. file.Close();
  125. // Enter the first versioncheck element. If the response contain more than one, ignore the rest. If the response doesen't contain any, fail.
  126. if (!fragment.EnterElement(versioncheck_elm))
  127. {
  128. return WRONG_XML;
  129. }
  130. /*
  131. const uni_char* version_att_str = fragment.GetAttribute(version_att);
  132. if(!version_att_str || uni_strcmp(version_att_str, AUTOUPDATE_XML_VERSION) != 0)
  133. {
  134. return WRONG_XML;
  135. }
  136. */
  137. while(fragment.EnterAnyElement())
  138. {
  139. XMLCompleteName element_name;
  140. element_name = fragment.GetElementName();
  141. if(element_name == resources_elm)
  142. {
  143. OpStatus::Ignore(ParseResourcesElement(fragment));
  144. }
  145. else if(element_name == file_elm || element_name == setting_elm)
  146. {
  147. const uni_char* resource_type = element_name.GetLocalPart();
  148. OP_ASSERT(resource_type);
  149. OpString resource_type_string;
  150. if (OpStatus::IsError(resource_type_string.Set(resource_type)))
  151. return PARSE_ERROR;
  152. OpStatus::Ignore(ParseResourceElement(resource_type_string, fragment));
  153. }
  154. fragment.LeaveElement();
  155. }
  156. fragment.LeaveElement();
  157. return SUCCESS;
  158. }
  159. ////////////////////////////////////////////////////////////////////////////////////////////////
  160. OP_STATUS StatusXMLDownloader::ParseResourcesElement(XMLFragment& fragment)
  161. {
  162. const XMLCompleteName downloadurl_elm(UNI_L("downloadurl"));
  163. if(fragment.EnterElement(downloadurl_elm))
  164. {
  165. const uni_char* text = fragment.GetText();
  166. RETURN_IF_ERROR(m_download_url.Set(text));
  167. fragment.LeaveElement();
  168. return OpStatus::OK;
  169. }
  170. return OpStatus::OK;
  171. }
  172. OP_STATUS StatusXMLDownloader::ParseResourceElement(const OpStringC& resource_type, XMLFragment& fragment)
  173. {
  174. OP_NEW_DBG("StatusXMLDownloader::ParseFileElement", "Autoupdate");
  175. UpdatableResource* resource = NULL;
  176. OpAutoPtr<UpdatableResource> keeper;
  177. RETURN_IF_ERROR(UpdatableResourceFactory::GetResourceFromXML(resource_type, fragment, &resource));
  178. keeper = resource;
  179. OP_ASSERT(resource);
  180. OP_DBG(("Found resource"));
  181. RETURN_IF_ERROR(m_resource_list.Add(keeper.get()));
  182. keeper.release();
  183. return OpStatus::OK;
  184. }
  185. ////////////////////////////////////////////////////////////////////////////////////////////////
  186. OP_STATUS StatusXMLDownloader::GetSubnodeText(XMLFragment* frag, const uni_char* node_name, OpString& text)
  187. {
  188. const XMLExpandedName elm(node_name);
  189. if (frag->EnterElement(elm))
  190. {
  191. const uni_char* ret = frag->GetText();
  192. frag->CloseElement();
  193. return text.Set(ret);
  194. }
  195. return OpStatus::ERR;
  196. }
  197. ////////////////////////////////////////////////////////////////////////////////////////////////
  198. StatusXMLDownloader::StatusXMLDownloader():
  199. m_check_type(CheckTypeInvalid),
  200. m_listener(NULL),
  201. m_transferItem(NULL),
  202. m_resource_iterator(0),
  203. m_status(READY)
  204. {
  205. }
  206. ////////////////////////////////////////////////////////////////////////////////////////////////
  207. StatusXMLDownloader::~StatusXMLDownloader()
  208. {
  209. StatusXMLDownloaderHolder::RemoveDownloader(this);
  210. if (m_transferItem && g_transferManager)
  211. {
  212. g_transferManager->ReleaseTransferItem(m_transferItem);
  213. }
  214. m_resource_list.DeleteAll();
  215. // Not much that we can do anyway
  216. OpStatus::Ignore(DeleteResponseFile());
  217. }
  218. ////////////////////////////////////////////////////////////////////////////////////////////////
  219. OP_STATUS StatusXMLDownloader::StartXMLRequest(const OpString& post_address, const OpString8& xml)
  220. {
  221. OP_ASSERT(m_response_file_name.HasContent());
  222. if (m_transferItem)
  223. {
  224. // An instance of this class can only hold one transferitem,
  225. // so it will refuse to start a second download until the first
  226. // transferitem is released.
  227. return OpStatus::ERR_NOT_SUPPORTED;
  228. }
  229. // Delete the old response file
  230. OpFile file;
  231. if (OpStatus::IsSuccess(file.Construct(m_response_file_name.CStr(), m_response_file_folder)))
  232. OpStatus::Ignore(file.Delete(FALSE));
  233. // Clear list of downloaded information
  234. m_resource_list.Clear();
  235. m_resource_iterator = 0;
  236. // Initiate transfer and listen in.
  237. RETURN_IF_ERROR(g_transferManager->GetNewTransferItem(&m_transferItem, post_address.CStr()));
  238. if (!m_transferItem)
  239. {
  240. m_status = NO_TRANSFERITEM;
  241. return OpStatus::ERR;
  242. }
  243. URL* url = m_transferItem->GetURL();
  244. if (!url)
  245. {
  246. m_status = NO_URL;
  247. return OpStatus::ERR;
  248. }
  249. url->SetHTTP_Method(HTTP_METHOD_POST);
  250. RETURN_IF_ERROR(url->SetHTTP_Data(xml.CStr(), TRUE));
  251. RETURN_IF_ERROR(url->SetHTTP_ContentType("application/x-www-form-urlencoded"));
  252. // Turn off UI interaction if the certificate is invalid.
  253. // This means that invalid certificates will not show a UI dialog but fail instead.
  254. RETURN_IF_ERROR(url->SetAttribute(URL::KBlockUserInteraction, TRUE));
  255. m_transferItem->SetTransferListener(this);
  256. URL tmp;
  257. if (url->Load(g_main_message_handler, tmp, TRUE, FALSE) != COMM_LOADING)
  258. {
  259. m_status = LOAD_FAILED;
  260. return OpStatus::ERR;
  261. }
  262. m_status = INPROGRESS;
  263. return OpStatus::OK;
  264. }
  265. ////////////////////////////////////////////////////////////////////////////////////////////////
  266. OP_STATUS StatusXMLDownloader::StopRequest()
  267. {
  268. if(m_transferItem)
  269. {
  270. m_transferItem->Stop();
  271. g_transferManager->ReleaseTransferItem(m_transferItem);
  272. m_transferItem = NULL;
  273. }
  274. return OpStatus::OK;
  275. }
  276. ////////////////////////////////////////////////////////////////////////////////////////////////
  277. UpdatableResource* StatusXMLDownloader::GetNextResource()
  278. {
  279. UpdatableResource* ret = NULL;
  280. if (m_resource_iterator < m_resource_list.GetCount())
  281. {
  282. ret = m_resource_list.Get(m_resource_iterator);
  283. m_resource_iterator++;
  284. }
  285. else
  286. {
  287. m_resource_iterator = 0;
  288. }
  289. return ret;
  290. }
  291. ////////////////////////////////////////////////////////////////////////////////////////////////
  292. OP_STATUS StatusXMLDownloader::RemoveResource(UpdatableResource* res)
  293. {
  294. INT32 indx = m_resource_list.Find(res);
  295. if(indx < 0)
  296. {
  297. return OpStatus::ERR;
  298. }
  299. if(m_resource_iterator > 0)
  300. {
  301. if((UINT32)indx < m_resource_iterator)
  302. {
  303. m_resource_iterator--;
  304. }
  305. }
  306. m_resource_list.Remove(indx);
  307. return OpStatus::OK;
  308. }
  309. UINT32 StatusXMLDownloader::GetResourceCount()
  310. {
  311. return m_resource_list.GetCount();
  312. }
  313. ////////////////////////////////////////////////////////////////////////////////////////////////
  314. void StatusXMLDownloader::OnProgress(OpTransferItem* transferItem, TransferStatus status)
  315. {
  316. OP_ASSERT(transferItem == m_transferItem);
  317. OP_ASSERT(m_response_file_name.HasContent());
  318. switch (status)
  319. {
  320. case TRANSFER_ABORTED:
  321. {
  322. m_status = DOWNLOAD_ABORTED;
  323. break;
  324. }
  325. case TRANSFER_FAILED:
  326. {
  327. m_status = DOWNLOAD_FAILED;
  328. break;
  329. }
  330. case TRANSFER_DONE:
  331. {
  332. OpString filename;
  333. OpString tmp_storage;
  334. filename.Set(g_folder_manager->GetFolderPathIgnoreErrors(m_response_file_folder, tmp_storage));
  335. filename.Append(m_response_file_name.CStr());
  336. m_transferItem->GetURL()->SaveAsFile(filename);
  337. #ifdef _DEBUG
  338. if(g_pcui->GetIntegerPref(PrefsCollectionUI::SaveAutoUpdateXML))
  339. {
  340. // Open xml response in a tab
  341. OpString url_string;
  342. OpString resolved;
  343. BOOL successful;
  344. url_string.Set(UNI_L("file:"));
  345. url_string.Append(filename);
  346. TRAPD(err, successful = g_url_api->ResolveUrlNameL(url_string, resolved));
  347. if (successful && resolved.Find("file://") == 0)
  348. {
  349. URL url = g_url_api->GetURL(resolved.CStr());
  350. URL ref_url = URL();
  351. BOOL3 open_in_new_window = YES;
  352. BOOL3 open_in_background = YES;
  353. Window* feedback_window;
  354. feedback_window = windowManager->GetAWindow(TRUE, open_in_new_window, open_in_background);
  355. feedback_window->OpenURL(url, DocumentReferrer(ref_url), TRUE, FALSE, -1, TRUE);
  356. }
  357. }
  358. #endif
  359. m_status = ParseDownloadedXML();
  360. break;
  361. }
  362. case TRANSFER_PROGRESS:
  363. default:
  364. {
  365. break;
  366. }
  367. }
  368. if (m_status == INPROGRESS)
  369. return; // Transfer not complete, wait for a useful callback.
  370. else
  371. {
  372. g_transferManager->ReleaseTransferItem(m_transferItem);
  373. m_transferItem = NULL;
  374. if (m_status == SUCCESS)
  375. m_listener->StatusXMLDownloaded(this);
  376. else
  377. m_listener->StatusXMLDownloadFailed(this, m_status);
  378. }
  379. }
  380. ////////////////////////////////////////////////////////////////////////////////////////////////
  381. OP_STATUS StatusXMLDownloader::ReplaceRedirectedFileURL(const OpString& url, const OpString& redirected_url)
  382. {
  383. OP_ASSERT(m_response_file_name.HasContent());
  384. OpFile file;
  385. RETURN_IF_ERROR(file.Construct(m_response_file_name.CStr(), m_response_file_folder));
  386. RETURN_IF_ERROR(file.Open(OPFILE_READ));
  387. // Define some element names for later use.
  388. const XMLCompleteName versioncheck_elm(UNI_L("urn:OperaAutoupdate"), UNI_L("oau"), UNI_L("versioncheck"));
  389. const XMLExpandedName file_elm(UNI_L("file"));
  390. // Parse downloaded xml.
  391. XMLFragment fragment;
  392. if (OpStatus::IsError(fragment.Parse(&file)))
  393. {
  394. file.Close();
  395. return OpStatus::ERR;
  396. }
  397. file.Close();
  398. // Enter the first versioncheck element. If the response contain more than one, ignore the rest. If the response doesen't contain any, fail.
  399. if (!fragment.EnterElement(versioncheck_elm))
  400. {
  401. return WRONG_XML;
  402. }
  403. BOOL replaced = FALSE;
  404. while(fragment.EnterAnyElement() && !replaced)
  405. {
  406. XMLCompleteName element_name;
  407. element_name = fragment.GetElementName();
  408. if(element_name == file_elm)
  409. {
  410. const XMLCompleteName url_elm(UNI_L("url"));
  411. while(fragment.EnterAnyElement() && !replaced)
  412. {
  413. XMLCompleteName element_name;
  414. element_name = fragment.GetElementName();
  415. if(element_name == url_elm)
  416. {
  417. const uni_char* text = fragment.GetText();
  418. if(url.Compare(text) == 0)
  419. {
  420. fragment.AddText(redirected_url.CStr());
  421. replaced = TRUE;
  422. }
  423. }
  424. fragment.LeaveElement();
  425. }
  426. }
  427. fragment.LeaveElement();
  428. }
  429. fragment.LeaveElement();
  430. if(replaced)
  431. {
  432. RETURN_IF_ERROR(file.Delete(FALSE));
  433. RETURN_IF_ERROR(file.Open(OPFILE_WRITE));
  434. ByteBuffer buffer;
  435. unsigned int bytes = 0;
  436. UINT32 chunk;
  437. OpString8 xml;
  438. RETURN_IF_ERROR(fragment.GetEncodedXML(buffer, TRUE, "utf-8", FALSE));
  439. for(chunk = 0; chunk < buffer.GetChunkCount(); chunk++)
  440. {
  441. char *chunk_ptr = buffer.GetChunk(chunk, &bytes);
  442. if(chunk_ptr)
  443. {
  444. RETURN_IF_ERROR(xml.Append(chunk_ptr, bytes));
  445. }
  446. }
  447. RETURN_IF_ERROR(file.Write(xml.CStr(), xml.Length()));
  448. RETURN_IF_ERROR(file.Close());
  449. }
  450. return OpStatus::OK;
  451. }
  452. ////////////////////////////////////////////////////////////////////////////////////////////////
  453. #endif // AUTO_UPDATE_SUPPORT