post.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #include "api.h"
  2. #include "../xml/obj_xml.h"
  3. #include "api_auth.h"
  4. #include "../nu/AutoChar.h"
  5. #include "../jnetlib/api_httpget.h"
  6. #include "ifc_authcallback.h"
  7. #include <api/service/waservicefactory.h>
  8. #include <strsafe.h>
  9. static const GUID internetConfigGroupGUID =
  10. {
  11. 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c }
  12. };
  13. #define USER_AGENT_SIZE (10 /*User-Agent*/ + 2 /*: */ + 6 /*Winamp*/ + 1 /*/*/ + 1 /*5*/ + 3/*.55*/ + 1 /*Null*/)
  14. static void SetUserAgent(api_httpreceiver *http)
  15. {
  16. char user_agent[USER_AGENT_SIZE] = {0};
  17. StringCchPrintfA(user_agent, USER_AGENT_SIZE, "User-Agent: Winamp/%S", WASABI_API_APP->main_getVersionNumString());
  18. http->addheader(user_agent);
  19. }
  20. #define HTTP_BUFFER_SIZE 8192
  21. static int FeedXMLHTTP(api_httpreceiver *http, obj_xml *parser, bool *noData)
  22. {
  23. char downloadedData[HTTP_BUFFER_SIZE] = {0};
  24. int xmlResult = API_XML_SUCCESS;
  25. int downloadSize = http->get_bytes(downloadedData, HTTP_BUFFER_SIZE);
  26. if (downloadSize)
  27. {
  28. xmlResult = parser->xmlreader_feed((void *)downloadedData, downloadSize);
  29. *noData=false;
  30. }
  31. else
  32. *noData = true;
  33. return xmlResult;
  34. }
  35. static int RunXMLDownload(api_httpreceiver *http, obj_xml *parser, ifc_authcallback *callback)
  36. {
  37. int ret;
  38. bool noData;
  39. do
  40. {
  41. if (callback && callback->OnIdle())
  42. {
  43. return AUTH_ABORT;
  44. }
  45. else if (!callback)
  46. {
  47. Sleep(50);
  48. }
  49. ret = http->run();
  50. if (FeedXMLHTTP(http, parser, &noData) != API_XML_SUCCESS)
  51. return AUTH_ERROR_PARSING_XML;
  52. }
  53. while (ret == HTTPRECEIVER_RUN_OK);
  54. // finish off the data
  55. do
  56. {
  57. if (FeedXMLHTTP(http, parser, &noData) != API_XML_SUCCESS)
  58. return AUTH_ERROR_PARSING_XML;
  59. } while (!noData);
  60. parser->xmlreader_feed(0, 0);
  61. if (ret != HTTPRECEIVER_RUN_ERROR)
  62. return AUTH_SUCCESS;
  63. else
  64. return AUTH_CONNECTIONRESET;
  65. }
  66. int PostXML(const char *url, const char *post_data, obj_xml *parser, ifc_authcallback *callback)
  67. {
  68. if (!parser)
  69. return AUTH_NOPARSER;
  70. api_httpreceiver *http = 0;
  71. waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
  72. if (sf)
  73. http = (api_httpreceiver *)sf->getInterface();
  74. if (!http)
  75. return AUTH_NOHTTP;
  76. int use_proxy = 1;
  77. bool proxy80 = AGAVE_API_CONFIG->GetBool(internetConfigGroupGUID, L"proxy80", false);
  78. if (proxy80 && strstr(url, ":") && (!strstr(url, ":80/") && strstr(url, ":80") != (url + strlen(url) - 3)))
  79. use_proxy = 0;
  80. const wchar_t *proxy = use_proxy?AGAVE_API_CONFIG->GetString(internetConfigGroupGUID, L"proxy", 0):0;
  81. size_t clen = strlen(post_data);
  82. http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, (proxy && proxy[0]) ? (const char *)AutoChar(proxy) : NULL);
  83. SetUserAgent(http);
  84. char clen_header[1024] = {0};
  85. StringCbPrintfA(clen_header, sizeof(clen_header), "Content-Length: %u", clen);
  86. http->addheader(clen_header);
  87. http->addheader("Content-Type: application/x-www-form-urlencoded; charset=UTF-8");
  88. if (callback && callback->OnConnecting())
  89. {
  90. sf->releaseInterface(http);
  91. return AUTH_ABORT;
  92. }
  93. http->connect(url, 0, "POST");
  94. // POST the data
  95. api_connection *connection = http->GetConnection();
  96. if (connection)
  97. {
  98. if (callback && callback->OnIdle())
  99. {
  100. sf->releaseInterface(http);
  101. return AUTH_ABORT;
  102. }
  103. else if (!callback)
  104. {
  105. Sleep(50);
  106. }
  107. if (http->run() == -1)
  108. goto connection_failed;
  109. if (callback && callback->OnSending())
  110. {
  111. sf->releaseInterface(http);
  112. return AUTH_ABORT;
  113. }
  114. const char *dataIndex = post_data;
  115. while (clen)
  116. {
  117. if (callback && callback->OnIdle())
  118. {
  119. sf->releaseInterface(http);
  120. return AUTH_ABORT;
  121. }
  122. else if (!callback)
  123. {
  124. Sleep(50);
  125. }
  126. if (http->run() == -1)
  127. goto connection_failed;
  128. size_t lengthToSend = min(clen, connection->GetSendBytesAvailable());
  129. if (lengthToSend)
  130. {
  131. connection->send(dataIndex, (int)lengthToSend);
  132. dataIndex+=lengthToSend;
  133. clen-=lengthToSend;
  134. }
  135. }
  136. }
  137. // retrieve reply
  138. if (callback && callback->OnReceiving())
  139. {
  140. sf->releaseInterface(http);
  141. return AUTH_ABORT;
  142. }
  143. int ret;
  144. do
  145. {
  146. if (callback && callback->OnIdle())
  147. {
  148. sf->releaseInterface(http);
  149. return AUTH_ABORT;
  150. }
  151. else if (!callback)
  152. {
  153. Sleep(50);
  154. }
  155. ret = http->run();
  156. if (ret == -1) // connection failed
  157. break;
  158. // ---- check our reply code ----
  159. int status = http->get_status();
  160. switch (status)
  161. {
  162. case HTTPRECEIVER_STATUS_CONNECTING:
  163. case HTTPRECEIVER_STATUS_READING_HEADERS:
  164. break;
  165. case HTTPRECEIVER_STATUS_READING_CONTENT:
  166. {
  167. int downloadError;
  168. downloadError = RunXMLDownload(http, parser, callback);
  169. sf->releaseInterface(http);
  170. return downloadError;
  171. }
  172. break;
  173. case HTTPRECEIVER_STATUS_ERROR:
  174. default:
  175. sf->releaseInterface(http);
  176. return AUTH_404;
  177. }
  178. }
  179. while (ret == HTTPRECEIVER_RUN_OK);
  180. connection_failed:
  181. sf->releaseInterface(http);
  182. return AUTH_404;
  183. }