utils.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #pragma once
  2. void *
  3. memmem_priv(const void *l, size_t l_len, const void *s, size_t s_len)
  4. {
  5. register char *cur, *last;
  6. const char *cl = (const char *)l;
  7. const char *cs = (const char *)s;
  8. /* we need something to compare */
  9. if (l_len == 0 || s_len == 0)
  10. return NULL;
  11. /* "s" must be smaller or equal to "l" */
  12. if (l_len < s_len)
  13. return NULL;
  14. /* special case where s_len == 1 */
  15. if (s_len == 1)
  16. return (void *)memchr(l, (int)*cs, l_len);
  17. /* the last position where its possible to find "s" in "l" */
  18. last = (char *)cl + l_len - s_len;
  19. for (cur = (char *)cl; cur <= last; cur++)
  20. if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
  21. return cur;
  22. return NULL;
  23. }
  24. static size_t header_callback_proxy(char *buffer, size_t size, size_t nitems, void *userdata)
  25. {
  26. BBS2chProxyConnection *conn = reinterpret_cast<BBS2chProxyConnection *>(userdata);
  27. if(conn->status > 0) return size*nitems;
  28. else if(conn->status == -1) {
  29. if(!memcmp(buffer,"\r\n",2)) {
  30. conn->status = 0;
  31. }
  32. return size*nitems;
  33. }
  34. PBBS2chProxyHttpHeaderEntry parsedHeader = BBS2chProxyHttpHeaders::parse(buffer, size*nitems);
  35. if (parsedHeader.get()) { // Looks like a header
  36. const std::string &headerName = parsedHeader->getLowercasedName();
  37. //fprintf(stderr, "%s\n", parsedHeader->getFull().c_str());
  38. if (headerName == "connection") {
  39. conn->socketToClient->writeString("Connection: Close\r\n");
  40. return size*nitems;
  41. }
  42. else if (headerName == "transfer-encoding") {
  43. if (parsedHeader->contains("chunked")) {
  44. if (allow_chunked && !conn->isClientHttp1_0) {
  45. conn->isResponseChunked = true;
  46. size_t ret = conn->socketToClient->write(buffer, size*nitems);
  47. return ret;
  48. }
  49. return size*nitems;
  50. }
  51. }
  52. else if (conn->force5ch && headerName == "set-cookie") {
  53. const char *ptr = (const char *)memmem_priv(buffer, size*nitems, "domain=", 7);
  54. if (ptr) {
  55. const char *end = ptr;
  56. while(*end != ';' && *end != '\r') end++;
  57. ptr = (const char *)memmem_priv(ptr, end-ptr, "5ch.net", 7);
  58. if (ptr) {
  59. conn->socketToClient->write(buffer, ptr-buffer);
  60. conn->socketToClient->write("2", 1);
  61. conn->socketToClient->write(ptr+1, size*nitems-(ptr+1-buffer));
  62. return size*nitems;
  63. }
  64. }
  65. }
  66. else if (conn->directDatDownloading && headerName == "content-type") {
  67. conn->socketToClient->writeString("Content-Type: text/plain\r\n");
  68. return size*nitems;
  69. }
  70. return conn->socketToClient->write(buffer, size*nitems);
  71. }
  72. else {
  73. bool shouldSendExtraHeaders = false;
  74. if (!strncasecmp("HTTP/", buffer, 5)) {
  75. const char *ptr = buffer + 5;
  76. const char *end = buffer + size*nitems;
  77. while (ptr < end && *ptr != ' ') ptr++;
  78. while (ptr < end && *ptr == ' ') ptr++;
  79. if (ptr < end) {
  80. int code = atoi(ptr);
  81. if (code == 100) {
  82. conn->status = -1;
  83. return size*nitems;
  84. } else if (code < 400) {
  85. shouldSendExtraHeaders = true;
  86. }
  87. }
  88. }
  89. if (!memcmp(buffer, "\r\n", 2)) {
  90. conn->status = 1;
  91. }
  92. size_t ret = conn->socketToClient->write(buffer, size*nitems);
  93. if (shouldSendExtraHeaders && conn->directDatDownloading == 2) {
  94. conn->socketToClient->writeString("Thread-Status: 1\r\n");
  95. conn->socketToClient->writeString("User-Status: 3\r\n");
  96. }
  97. return ret;
  98. }
  99. }
  100. static size_t write_callback_proxy(char *buffer, size_t size, size_t nitems, void *userdata)
  101. {
  102. BBS2chProxyConnection *conn = reinterpret_cast<BBS2chProxyConnection *>(userdata);
  103. if(conn->isResponseChunked) {
  104. char buf[64];
  105. snprintf(buf, 64, "%lx\r\n", size*nitems);
  106. conn->socketToClient->write(buf, strlen(buf));
  107. }
  108. size_t ret = conn->socketToClient->write(buffer, size*nitems);
  109. if(conn->isResponseChunked) conn->socketToClient->writeString("\r\n");
  110. return ret;
  111. }
  112. static size_t header_callback_download(char *buffer, size_t size, size_t nitems, void *userdata)
  113. {
  114. BBS2chProxyHttpHeaders *headers = static_cast<BBS2chProxyHttpHeaders *>(userdata);
  115. PBBS2chProxyHttpHeaderEntry parsedHeader = BBS2chProxyHttpHeaders::parse(buffer, size*nitems);
  116. if (parsedHeader.get()) { // Looks like a header
  117. const std::string &headerName = parsedHeader->getLowercasedName();
  118. if (headerName == "connection") {
  119. if (headers) headers->add(parsedHeader->getName(), "close");
  120. return size*nitems;
  121. }
  122. else if (headerName == "transfer-encoding") {
  123. if (parsedHeader->contains("chunked")) {
  124. return size*nitems;
  125. }
  126. }
  127. if (headers) headers->add(parsedHeader->getName(), parsedHeader->getValue());
  128. }
  129. else if (headers) headers->setStatusLine(buffer, size*nitems);
  130. return size*nitems;
  131. }
  132. static size_t write_callback_download(char *buffer, size_t size, size_t nitems, void *userdata)
  133. {
  134. std::vector<char> *data = static_cast<std::vector<char> *>(userdata);
  135. size_t downloaded = size*nitems;
  136. if (data) data->insert(data->end(), buffer, buffer+downloaded);
  137. return downloaded;
  138. }
  139. static size_t read_callback_proxy(char *buffer, size_t size, size_t nitems, void *userdata)
  140. {
  141. BBS2chProxyConnection *conn = reinterpret_cast<BBS2chProxyConnection *>(userdata);
  142. if (size*nitems < 1) return 0;
  143. if (conn->isClientChunked) {
  144. size_t chunkSize;
  145. char tmp[64];
  146. if (!conn->content_length) {
  147. if (!conn->socketToClient->readLine(tmp, 64)) return 0;
  148. chunkSize = strtol(tmp, NULL, 16);
  149. if (chunkSize == 0) {
  150. return 0;
  151. }
  152. }
  153. else {
  154. chunkSize = conn->content_length;
  155. conn->content_length = 0;
  156. }
  157. if (chunkSize <= size*nitems) {
  158. size_t ret = conn->socketToClient->read(buffer, chunkSize);
  159. if (ret <= 0) return 0;
  160. conn->socketToClient->readLine(tmp, 64);
  161. return ret;
  162. }
  163. else {
  164. size_t ret = conn->socketToClient->read(buffer, size*nitems);
  165. if (ret <= 0) return 0;
  166. conn->content_length = chunkSize - ret;
  167. return ret;
  168. }
  169. }
  170. else if (conn->content_length) {
  171. size_t bytesToRead = conn->content_length;
  172. if (size*nitems < conn->content_length) bytesToRead = size*nitems;
  173. size_t ret = conn->socketToClient->read(buffer, bytesToRead);
  174. conn->content_length -= ret;
  175. return ret;
  176. }
  177. return 0;
  178. }
  179. double getCurrentTime(void)
  180. {
  181. #ifdef _WIN32
  182. FILETIME ft;
  183. GetSystemTimeAsFileTime(&ft);
  184. unsigned long long now = ft.dwHighDateTime;
  185. now <<= 32;
  186. now |= ft.dwLowDateTime;
  187. return (double)(now * 1e-7 - 11644473600.0);
  188. #else
  189. struct timeval tv;
  190. gettimeofday(&tv, NULL);
  191. return (double)(tv.tv_sec + tv.tv_usec * 1e-6);
  192. #endif
  193. }
  194. static size_t readChunkedBodyIntoBuffer(char **bufferOut, IBBS2chProxySocket *socket)
  195. {
  196. size_t contentLength = 0;
  197. size_t bufferLength = 128;
  198. size_t chunkSize = 0;
  199. char tmp[64];
  200. char *buffer = (char *)malloc(bufferLength);
  201. while (1) {
  202. if (!chunkSize) {
  203. if (!socket->readLine(tmp, 64)) break;
  204. chunkSize = strtol(tmp, NULL, 16);
  205. if (chunkSize == 0) {
  206. break;
  207. }
  208. if (chunkSize + contentLength >= bufferLength) {
  209. bufferLength = chunkSize + contentLength + 1;
  210. buffer = (char *)realloc(buffer, bufferLength);
  211. }
  212. }
  213. size_t ret = socket->read(buffer+contentLength, chunkSize);
  214. if (ret > 0) contentLength += ret;
  215. if (ret < chunkSize) break;
  216. if (!socket->readLine(tmp, 64)) break;
  217. chunkSize = 0;
  218. }
  219. buffer[contentLength] = 0;
  220. if (bufferOut) *bufferOut = buffer;
  221. else free(buffer);
  222. return contentLength;
  223. }