1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102 |
- #include "BBS2chProxyPoster.h"
- #include <vector>
- #include <map>
- #include <sstream>
- #include <algorithm>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #ifdef _WIN32
- #include <windows.h>
- #endif
- #ifdef USE_LUA
- #include <lua.hpp>
- #endif
- #include "BBS2chProxyAuth.h"
- #include "BBS2chProxyKeyManager.h"
- #include "hmac.h"
- #include "stringEncodingConverter.h"
- #include "parson/parson.h"
- extern char *proxy_server;
- extern long proxy_port;
- extern long proxy_type;
- extern long timeout;
- extern char *user_agent;
- extern int force_ipv4;
- extern char *appKey;
- extern char *hmacKey;
- extern unsigned int api_mode;
- extern BBS2chProxyHttpHeaders bbscgi_headers;
- extern std::vector<std::string> bbscgi_postorder;
- extern unsigned int bbscgi_utf8;
- extern char *lua_script;
- extern int allow_chunked;
- extern CURLSH *curl_share;
- extern int manage_bbscgi_cookies;
- extern unsigned int curl_version_number;
- extern void log_printf(int level, const char *format ...);
- extern double getCurrentTime(void);
- static size_t header_callback_bbscgi(char *buffer, size_t size, size_t nitems, void *userdata)
- {
- BBS2chProxy5chPoster *poster = static_cast<BBS2chProxy5chPoster *>(userdata);
- BBS2chProxyConnection *conn = poster->connectionDelegate;
- if(poster->_status > 255) return size*nitems;
- else if(poster->_status == -1) {
- if(!memcmp(buffer,"\r\n",2)) {
- poster->_status = 0;
- }
- return size*nitems;
- }
- PBBS2chProxyHttpHeaderEntry parsedHeader = BBS2chProxyHttpHeaders::parse(buffer, size*nitems);
- if (parsedHeader) { // Looks like a header
- const std::string &headerName = parsedHeader->getLowercasedName();
- //fprintf(stderr, "%s\n", parsedHeader->getFull().c_str());
- if (headerName == "connection") {
- poster->_responseHeaders.append("Connection: Close\r\n");
- return size*nitems;
- }
- else if (headerName == "transfer-encoding") {
- if (parsedHeader->contains("chunked")) {
- if (allow_chunked && !conn->isClientHttp1_0) {
- poster->_isResponseChunked = true;
- poster->_responseHeaders.append(buffer, size*nitems);
- }
- return size*nitems;
- }
- }
- else if (headerName == "set-cookie") {
- poster->_hasSetCookie = true;
- if (conn->force5ch) {
- std::string value = parsedHeader->getFull(true);
- size_t start = value.find("domain=");
- if (start != std::string::npos) {
- start += 7;
- size_t end = value.find(";", start);
- size_t pos = value.find(".5ch.net", start);
- if (pos != std::string::npos && (end == std::string::npos || pos < end)) {
- value[start+1] = '2';
- poster->_responseHeaders.append(value);
- return size*nitems;
- }
- }
- }
- }
- else if (headerName == "x-chx-error") {
- const std::string &headerValue = parsedHeader->getValue();
- const char *ptr = headerValue.c_str();
- log_printf(0, "Posting to bbs.cgi has been cancelled. Reason: %s\n", ptr);
- if (*ptr == 'E') {
- int code = atoi(ptr+1);
- if ((code >= 3310 && code <= 3311) || /* inconsistent with User-Agent or something? */
- (code >= 3320 && code <= 3324) || /* key expiration? */
- (code >= 3390 && code <= 3392)) /* 3390: BAN, 3391-3392: key expiration? */
- {
- BBS2chProxyConnection::keyManager.setKey("", poster->_monaKeyForRequest, poster->_userAgentForRequest, code);
- if (poster->_isFirstRun) {
- poster->_status = 1;
- }
- }
- } else if (poster->_manageCookies) {
- int code = atoi(ptr);
- if ((code == 1932) && poster->_isFirstRun) { // was 1930, 1931
- poster->_status = 2;
- }
- }
- }
- else if (headerName == "x-monakey") {
- BBS2chProxyConnection::keyManager.setKey(parsedHeader->getValue(), poster->_monaKeyForRequest, poster->_userAgentForRequest, 0);
- }
- poster->_responseHeaders.append(buffer, size*nitems);
- return size*nitems;
- }
- else {
- if (!strncasecmp("HTTP/", buffer, 5)) {
- const char *ptr = buffer + 5;
- const char *end = buffer + size*nitems;
- while (ptr < end && *ptr != ' ') ptr++;
- while (ptr < end && *ptr == ' ') ptr++;
- if (ptr < end) {
- int code = atoi(ptr);
- if (code == 100) {
- poster->_status = -1;
- return size*nitems;
- }
- }
- }
- poster->_responseHeaders.append(buffer, size*nitems);
- if (!memcmp(buffer, "\r\n", 2)) {
- if (poster->_status == 0) {
- conn->socketToClient->write(poster->_responseHeaders.data(), poster->_responseHeaders.size());
- poster->_status = 256;
- }
- else return 0;
- }
- return size*nitems;
- }
- }
- static size_t write_callback_proxy(char *buffer, size_t size, size_t nitems, void *userdata)
- {
- BBS2chProxy5chPoster *poster = static_cast<BBS2chProxy5chPoster *>(userdata);
- BBS2chProxyConnection *conn = poster->connectionDelegate;
- if(poster->_isResponseChunked) {
- char buf[64];
- snprintf(buf, 64, "%lx\r\n", size*nitems);
- conn->socketToClient->write(buf, strlen(buf));
- }
- size_t ret = conn->socketToClient->write(buffer, size*nitems);
- if(poster->_isResponseChunked) conn->socketToClient->writeString("\r\n");
- return ret;
- }
- static size_t header_callback_download(char *buffer, size_t size, size_t nitems, void *userdata)
- {
- BBS2chProxyHttpHeaders *headers = static_cast<BBS2chProxyHttpHeaders *>(userdata);
- PBBS2chProxyHttpHeaderEntry parsedHeader = BBS2chProxyHttpHeaders::parse(buffer, size*nitems);
- if (parsedHeader.get()) { // Looks like a header
- const std::string &headerName = parsedHeader->getLowercasedName();
- if (headerName == "connection") {
- if (headers) headers->add(parsedHeader->getName(), "close");
- return size*nitems;
- }
- else if (headerName == "transfer-encoding") {
- if (parsedHeader->contains("chunked")) {
- return size*nitems;
- }
- }
- if (headers) headers->add(parsedHeader->getName(), parsedHeader->getValue());
- }
- else if (headers) headers->setStatusLine(buffer, size*nitems);
- return size*nitems;
- }
- static size_t write_callback_download(char *buffer, size_t size, size_t nitems, void *userdata)
- {
- std::vector<char> *data = static_cast<std::vector<char> *>(userdata);
- size_t downloaded = size*nitems;
- if (data) data->insert(data->end(), buffer, buffer+downloaded);
- return downloaded;
- }
- static bool isValidAsUTF8(const char *input, size_t inputLength) {
- for (int i=0; i<inputLength; i++) {
- unsigned char c1 = input[i];
- if (c1 < 0x80) continue;
- else if (c1 >= 0xc2 && c1 <= 0xdf) {
- if (i >= inputLength - 1) return false;
- unsigned char c2 = input[++i];
- if (c2 < 0x80 || c2 > 0xbf) return false;
- unsigned int unicode = c2 & 0xf;
- unicode |= (((c2 >> 4) & 0x3) | ((c1 & 0x3) << 2)) << 4;
- unicode |= ((c1 >> 2) & 0x7) << 8;
- if (unicode < 0x80 || unicode > 0x7ff) return false;
- }
- else if (c1 >= 0xe0 && c1 <= 0xef) {
- if (i >= inputLength - 2) return false;
- unsigned char c2 = input[++i];
- if (c2 < 0x80 || c2 > 0xbf) return false;
- unsigned char c3 = input[++i];
- if (c3 < 0x80 || c3 > 0xbf) return false;
- unsigned int unicode = c3 & 0xf;
- unicode |= (((c3 >> 4) & 0x3) | ((c2 & 0x3) << 2)) << 4;
- unicode |= ((c2 >> 2) & 0xf) << 8;
- unicode |= (c1 & 0xf) << 12;
- if (unicode < 0x800 || unicode > 0xffff) return false;
- else if (unicode >= 0xd800 && unicode <= 0xdfff) return false; /* for surrogate pairs */
- }
- else if (c1 >= 0xf0 && c1 <= 0xf7) {
- if (i >= inputLength - 3) return false;
- unsigned char c2 = input[++i];
- if (c2 < 0x80 || c2 > 0xbf) return false;
- unsigned char c3 = input[++i];
- if (c3 < 0x80 || c3 > 0xbf) return false;
- unsigned char c4 = input[++i];
- if (c4 < 0x80 || c4 > 0xbf) return false;
- unsigned int unicode = c4 & 0xf;
- unicode |= (((c4 >> 4) & 0x3) | ((c3 & 0x3) << 2)) << 4;
- unicode |= ((c3 >> 2) & 0xf) << 8;
- unicode |= (c2 & 0xf) << 12;
- unicode |= (((c2 >> 4) & 0x3) | ((c1 & 0x3) << 2)) << 16;
- unicode |= ((c1 >> 2) & 0x1) << 20;
- if (unicode < 0x10000 || unicode > 0x10ffff) return false;
- }
- else return false;
- }
- return true;
- }
- static void appendPostSignature(BBS2chProxyFormData &body, const std::string &userAgent, const std::string &monaKey, BBS2chProxyHttpHeaders &headers, bool forTalk)
- {
- char nonce[32];
- std::string message;
- if (!forTalk) {
- snprintf(nonce, 32, "%.3f", getCurrentTime());
- message.append(body["bbs"]);
- message.append("<>");
- message.append(body["key"]);
- message.append("<>");
- message.append(body["time"]);
- message.append("<>");
- message.append(body["FROM"]);
- message.append("<>");
- message.append(body["mail"]);
- message.append("<>");
- message.append(body["MESSAGE"]);
- message.append("<>");
- message.append(body["subject"]);
- message.append("<>");
- message.append(userAgent);
- message.append("<>");
- message.append(monaKey);
- message.append("<>");
- message.append("<>");
- message.append(nonce);
- } else {
- message.append(body["bbs"]);
- message.append("<>");
- message.append(body["key"]);
- message.append("<>");
- message.append(body["subject"]);
- message.append("<>");
- message.append(body["MESSAGE"]);
- message.append("<>");
- message.append(body["time"]);
- message.append("<>");
- message.append(body["sid"]);
- message.append("<>");
- }
- unsigned char digest[32];
- char digestStr[65];
- static const char *table = "0123456789abcdef";
- proxy2ch_HMAC_SHA256(hmacKey, strlen(hmacKey), message.data(), message.length(), digest);
- for (int i=0; i<32; i++) {
- unsigned char c = digest[i];
- unsigned char upper = (c >> 4) & 0xf;
- unsigned char lower = c & 0xf;
- digestStr[i*2] = table[upper];
- digestStr[i*2+1] = table[lower];
- }
- digestStr[64] = 0;
- if (!forTalk) {
- headers.set("X-APIKey", appKey);
- log_printf(1, "Appended header \"X-APIKey: %s\"\n", appKey);
- headers.set("X-PostSig", digestStr);
- log_printf(1, "Appended header \"X-PostSig: %s\"\n", digestStr);
- headers.set("X-PostNonce", nonce);
- log_printf(1, "Appended header \"X-PostNonce: %s\"\n", nonce);
- headers.set("X-MonaKey", monaKey);
- log_printf(1, "Appended header \"X-MonaKey: %s\"\n", monaKey.c_str());
- } else {
- headers.set("X-Write-Token", digestStr);
- log_printf(1, "Appended header \"X-Write-Token: %s\"\n", digestStr);
- if (monaKey != "00000000-0000-0000-0000-000000000000") {
- headers.set("X-Write-Key", monaKey);
- log_printf(1, "Appended header \"X-Write-Key: %s\"\n", monaKey.c_str());
- }
- }
- }
- static bool convertBodyToUTF8(BBS2chProxyFormData &body)
- {
- bool shouldConvertToUTF8 = true;
- bool shouldCheckWholeBody = true;
- const std::string &submit = body.get("submit");
- if (body.getEncoded("submit").size() != submit.size()) {
- if (isValidAsUTF8(submit.data(), submit.size())) {
- shouldConvertToUTF8 = false;
- }
- shouldCheckWholeBody = false;
- }
- if (shouldCheckWholeBody) {
- shouldConvertToUTF8 = false;
- for (BBS2chProxyFormData::iterator it = body.begin(); it != body.end(); ++it) {
- if (it->second.empty()) continue;
- if (!isValidAsUTF8(it->second.get().data(), it->second.get().size())) {
- shouldConvertToUTF8 = true;
- break;
- }
- }
- }
- if (shouldConvertToUTF8) {
- for (BBS2chProxyFormData::iterator it = body.begin(); it != body.end(); ++it) {
- if (it->second.empty()) continue;
- char *converted = convertShiftJISToUTF8(it->second.get().data(), it->second.get().size());
- if (converted) {
- it->second = std::string(converted);
- free(converted);
- }
- }
- }
- return shouldConvertToUTF8;
- }
- #if LIBCURL_VERSION_NUM >= 0x070e01 /* curl 7.14.1 or later */
- static void appendCurlCookiesToJar(CURL *curl, BBS2chProxyKeyManager::CookieJar &jar)
- {
- struct curl_slist *cookies = NULL;
- if (!curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies) && cookies) {
- struct curl_slist *each = cookies;
- jar.lock();
- jar.clear();
- while (each) {
- BBS2chProxyKeyManager::Cookie cookie(each->data);
- jar.set(cookie);
- each = each->next;
- }
- jar.unlock();
- BBS2chProxyConnection::keyManager.flushCookies();
- curl_slist_free_all(cookies);
- }
- }
- #endif
- #ifdef USE_LUA
- extern "C" {
- static int lua_hmacSHA256(lua_State *l)
- {
- static const char *table = "0123456789abcdef";
- size_t keyLength, dataLength;
- const char *key = luaL_checklstring(l, 1, &keyLength);
- const char *data = luaL_checklstring(l, 2, &dataLength);
- if (!key || !data) return 0;
- unsigned char digest[32];
- char digestStr[65];
- proxy2ch_HMAC_SHA256(key, keyLength, data, dataLength, digest);
- for (int i=0; i<32; i++) {
- unsigned char c = digest[i];
- unsigned char upper = (c >> 4) & 0xf;
- unsigned char lower = c & 0xf;
- digestStr[i*2] = table[upper];
- digestStr[i*2+1] = table[lower];
- }
- digestStr[64] = 0;
- lua_pushstring(l, digestStr);
- return 1;
- }
- static int lua_decodeURIComponent(lua_State *l)
- {
- size_t length;
- const char *input = luaL_checklstring(l, 1, &length);
- if (!input) return 0;
- bool decodePlus = true;
- if (!lua_isnoneornil(l, 2)) {
- decodePlus = (lua_toboolean(l, 2));
- }
- std::string output = BBS2chProxyFormData::decodeURIComponent(input, length, decodePlus);
- lua_pushstring(l, output.c_str());
- return 1;
- }
- static int lua_encodeURIComponent(lua_State *l)
- {
- size_t length;
- const char *input = luaL_checklstring(l, 1, &length);
- if (!input) return 0;
- bool spaceAsPlus = true;
- if (!lua_isnoneornil(l, 2)) {
- spaceAsPlus = (lua_toboolean(l, 2));
- }
- std::string output = BBS2chProxyFormData::encodeURIComponent(input, length, spaceAsPlus);
- lua_pushstring(l, output.c_str());
- return 1;
- }
- static int lua_convertShiftJISToUTF8(lua_State *l)
- {
- size_t length;
- const char *input = luaL_checklstring(l, 1, &length);
- if (!input) return 0;
- if (length > 0) {
- char *output = convertShiftJISToUTF8(input, length);
- if (!output) lua_pushnil(l);
- else {
- lua_pushstring(l, output);
- free(output);
- }
- }
- else lua_pushstring(l, "");
- return 1;
- }
- static int lua_isExpiredKey(lua_State *l)
- {
- size_t length;
- const char *input = luaL_checklstring(l, 1, &length);
- if (!input) return 0;
- if (BBS2chProxyConnection::keyManager.isExpired(input)) {
- lua_pushboolean(l, 1);
- }
- else lua_pushboolean(l, 0);
- return 1;
- }
- static int lua_isValidAsUTF8(lua_State *l)
- {
- size_t length;
- const char *input = luaL_checklstring(l, 1, &length);
- if (!input) return 0;
- lua_pushboolean(l, isValidAsUTF8(input, length));
- return 1;
- }
- static int lua_getMonaKey(lua_State *l)
- {
- size_t length;
- const char *input = luaL_checklstring(l, 1, &length);
- if (!input) return 0;
- const std::string &key = BBS2chProxyConnection::keyManager.getKey(input);
- lua_pushstring(l, key.c_str());
- return 1;
- }
- static int lua_getSID(lua_State *l)
- {
- const std::string &sid = BBS2chProxyConnection::auth.getSID();
- lua_pushstring(l, sid.c_str());
- return 1;
- }
- }
- #endif
- IBBS2chProxyPoster::IBBS2chProxyPoster(BBS2chProxyHttpHeaders &headers, BBS2chProxyFormData &body, BBS2chProxyConnection *delegate)
- : _requestHeaders(headers), _requestBody(body), _verbose(0), connectionDelegate(delegate), _manageCookies(false)
- {
- prepareHeadersAndBody();
- }
- BBS2chProxy5chPoster::BBS2chProxy5chPoster(BBS2chProxyURL &url, BBS2chProxyHttpHeaders &headers, BBS2chProxyFormData &body, BBS2chProxyConnection *delegate)
- : IBBS2chProxyPoster(headers, body, delegate), _isFirstRun(true), _status(0), _isResponseChunked(false), _hasSetCookie(false)
- {
- _url = url.absoluteString();
- }
- BBS2chProxyTalkPoster::BBS2chProxyTalkPoster(BBS2chProxyURL &url, BBS2chProxyHttpHeaders &headers, BBS2chProxyFormData &body, BBS2chProxyConnection *delegate)
- : IBBS2chProxyPoster(headers, body, delegate)
- {
- _url = "https://api.talk-platform.com/v1/bbs.cgi";
- _requestBody.remove("sid");
- }
- BBS2chProxyTalkTo5chPoster::BBS2chProxyTalkTo5chPoster(BBS2chProxyURL &url, BBS2chProxyHttpHeaders &headers, BBS2chProxyFormData &body, BBS2chProxyConnection *delegate)
- : BBS2chProxy5chPoster(url, headers, body, delegate)
- {
- }
- void IBBS2chProxyPoster::prepareHeadersAndBody()
- {
- _host = _requestHeaders.get("Host");
- _board = _requestBody.get("bbs");
- _thread = _requestBody.get("key");
- if (!bbscgi_postorder.empty()) {
- _requestBody.reorder(bbscgi_postorder);
- log_printf(1, "Reordered request body is: %s\n", _requestBody.toString().c_str());
- }
- _requestHeaders.remove("Host");
- if (user_agent) _requestHeaders.set("User-Agent", user_agent);
- if (!bbscgi_headers.empty()) {
- for (std::map<std::string, PBBS2chProxyHttpHeaderEntry>::iterator it = bbscgi_headers.getMap().begin(); it != bbscgi_headers.getMap().end(); it++) {
- /* we create a copy of entry here, because the original entry shouldn't be modified */
- PBBS2chProxyHttpHeaderEntry entry(new BBS2chProxyHttpHeaderEntry(*it->second.get()));
- if (!_host.empty()) {
- entry->replaceValue("%HOST%", _host);
- }
- if (!_board.empty()) {
- entry->replaceValue("%BOARD%", _board);
- }
- if (!_thread.empty()) {
- entry->replaceValue("%THREAD%", _thread);
- }
- _requestHeaders.set(entry);
- log_printf(1, "Appended custom header \"%s\"\n", entry->getFull().c_str());
- }
- }
- }
- curl_slist* IBBS2chProxyPoster::prepareCurlHandle(BBS2chProxyHttpHeaders &headers, BBS2chProxyFormData &body, curl_slist* headersForCurl)
- {
- CURL *curl = connectionDelegate->curl;
- #if LIBCURL_VERSION_NUM >= 0x070e01 /* curl 7.14.1 or later */
- if (_manageCookies) {
- log_printf(1, "Cookies are managed by proxy2ch, most of existing \"Cookie: \" headers are ignored.\n");
- curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); //enable cookie engine explicitly
- curl_easy_setopt(curl, CURLOPT_COOKIELIST, "ALL"); //erase all cookies explicitly
- if (headers.has("Cookie")) {
- const std::string &value = headers.getEntry("Cookie")->getValue();
- std::vector<std::string> list;
- size_t offset = 0;
- while (1) {
- size_t pos = value.find("; ", offset);
- if (pos == std::string::npos) {
- list.push_back(value.substr(offset));
- break;
- }
- list.push_back(value.substr(offset, pos - offset));
- offset = pos + 2;
- }
- std::string newCookie;
- for (std::vector<std::string>::iterator it = list.begin(); it != list.end(); ++it) {
- size_t pos = it->find('=');
- if (pos == std::string::npos) continue;
- std::string name = it->substr(0, pos);
- if (name == "DMDM" || name == "MDMD" || name == "sid") {
- if (newCookie.size()) newCookie += "; ";
- newCookie += *it;
- }
- }
- if (newCookie.size()) curl_easy_setopt(curl, CURLOPT_COOKIE, newCookie.c_str());
- headers.remove("Cookie");
- }
- BBS2chProxyKeyManager::CookieJar &jar = BBS2chProxyConnection::keyManager.getCookieJar(_userAgentForRequest);
- jar.lock();
- std::vector<BBS2chProxyKeyManager::Cookie> &list = jar.getList();
- for (std::vector<BBS2chProxyKeyManager::Cookie>::iterator it = list.begin(); it != list.end(); ++it) {
- if (!it->isExpired()) curl_easy_setopt(curl, CURLOPT_COOKIELIST, it->valueInNetscapeFormat().c_str());
- }
- jar.unlock();
- }
- #endif
- headersForCurl = headers.appendToCurlSlist(headersForCurl);
- if (!headers.has("Expect")) headersForCurl = curl_slist_append(headersForCurl, "Expect:");
- if (!headers.has("Accept")) headersForCurl = curl_slist_append(headersForCurl, "Accept:");
- if (curl_share) curl_easy_setopt(curl, CURLOPT_SHARE, curl_share);
- curl_easy_setopt(curl, CURLOPT_URL, _url.c_str());
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
- curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
- curl_easy_setopt(curl, CURLOPT_POST, 1L);
- curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.toString().c_str());
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
- curl_easy_setopt(curl, CURLOPT_VERBOSE, _verbose);
- if (force_ipv4) curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
- curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headersForCurl);
- if (!_nic.empty()) curl_easy_setopt(curl, CURLOPT_INTERFACE, _nic.c_str());
- if (!_forceProxy.empty()) {
- curl_easy_setopt(curl, CURLOPT_PROXY, _forceProxy.c_str());
- }
- else if (proxy_server) {
- curl_easy_setopt(curl, CURLOPT_PROXY, proxy_server);
- curl_easy_setopt(curl, CURLOPT_PROXYPORT, proxy_port);
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, proxy_type);
- }
- return headersForCurl;
- }
- void IBBS2chProxyPoster::runLuaScript(BBS2chProxyHttpHeaders &headers, BBS2chProxyFormData &body)
- {
- #ifdef USE_LUA
- lua_State* l = luaL_newstate();
- luaL_openlibs(l);
- if (luaL_loadfile(l, lua_script) != LUA_OK) {
- log_printf(0, "Lua: Failed to open script %s:\n %s\n", lua_script, lua_tostring(l, -1));
- goto lua_end;
- }
- lua_newtable(l);
- lua_pushcfunction(l, lua_hmacSHA256);
- lua_setfield(l, -2, "hmacSHA256");
- lua_pushcfunction(l, lua_decodeURIComponent);
- lua_setfield(l, -2, "decodeURIComponent");
- lua_pushcfunction(l, lua_encodeURIComponent);
- lua_setfield(l, -2, "encodeURIComponent");
- lua_pushcfunction(l, lua_convertShiftJISToUTF8);
- lua_setfield(l, -2, "convertShiftJISToUTF8");
- lua_pushcfunction(l, lua_isExpiredKey);
- lua_setfield(l, -2, "isExpiredKey");
- lua_pushcfunction(l, lua_isValidAsUTF8);
- lua_setfield(l, -2, "isValidAsUTF8");
- lua_pushcfunction(l, lua_getMonaKey);
- lua_setfield(l, -2, "getMonaKey");
- lua_pushcfunction(l, lua_getSID);
- lua_setfield(l, -2, "getSID");
- lua_pushstring(l, BBS2chProxyConnection::keyManager.getKey().c_str());
- lua_setfield(l, -2, "monaKey");
- lua_pushinteger(l, connectionDelegate->serverPort);
- lua_setfield(l, -2, "port");
- lua_setglobal(l, "proxy2ch");
- BBS2chProxyHttpHeaders::getClassDefinitionForLua(l);
- lua_setglobal(l, "HttpHeaders");
- if (lua_pcall(l, 0, 0, 0) != LUA_OK) {
- log_printf(0, "Lua: Failed to run script %s:\n %s\n", lua_script, lua_tostring(l, -1));
- goto lua_end;
- }
- lua_getglobal(l, "willSendRequestToBbsCgi");
- if (!lua_isfunction(l, -1)) {
- log_printf(0, "Lua: willSendRequestToBbsCgi function does not exist in the script\n");
- goto lua_end;
- }
- lua_newtable(l);
- headers.getUserdataForLua(l);
- lua_setfield(l, -2, "headers");
- lua_pushstring(l, body.toString().c_str());
- lua_setfield(l, -2, "body");
- lua_pushstring(l, _host.c_str());
- lua_pushstring(l, _board.c_str());
- lua_pushstring(l, _thread.c_str());
- if (lua_pcall(l, 4, 1, 0) != LUA_OK) {
- log_printf(0, "Lua: Failed to call willSendRequestToBbsCgi function:\n %s\n", lua_tostring(l, -1));
- goto lua_end;
- }
- if (!lua_istable(l, -1)) {
- log_printf(0, "Lua: A return type of willSendRequestToBbsCgi function should be a table\n");
- goto lua_end;
- }
- lua_pushstring(l, "body");
- lua_rawget(l, -2);
- if (lua_isstring(l, -1)) {
- size_t length;
- const char *newBody = lua_tolstring(l, -1, &length);
- body = BBS2chProxyFormData(newBody, length);
- log_printf(1, "Lua: Set request body \"%s\"\n", newBody);
- }
- lua_pop(l, 1);
- lua_pushstring(l, "headers");
- lua_rawget(l, -2);
- if (lua_istable(l, -1)) {
- headers = BBS2chProxyHttpHeaders();
- lua_pushnil(l);
- while (lua_next(l, -2)) {
- if (lua_isstring(l, -1) && lua_isstring(l, -2)) {
- const char *name = lua_tostring(l, -2);
- const char *value = lua_tostring(l, -1);
- headers.add(name, value);
- log_printf(1, "Lua: Set request header \"%s: %s\"\n", name, value);
- }
- lua_pop(l, 1);
- }
- }
- else if (lua_isuserdata(l, -1)) {
- if (lua_getmetatable(l, -1)) {
- #if LUA_VERSION_NUM > 502
- if (lua_getfield(l, -1, "_type") == LUA_TSTRING)
- #else
- if (lua_getfield(l, -1, "_type"), lua_type(l, -1) == LUA_TSTRING)
- #endif
- {
- if (!strcmp(lua_tostring(l, -1), "HttpHeaders")) {
- BBS2chProxyHttpHeaders *newHeaders = *((BBS2chProxyHttpHeaders **)lua_touserdata(l, -3));
- if (newHeaders != &headers) {
- headers = *newHeaders;
- }
- for (BBS2chProxyHttpHeaders::iterator it = headers.begin(); it != headers.end(); ++it) {
- log_printf(1, "Lua: Set request header \"%s\"\n", it->second.c_str());
- }
- }
- }
- lua_pop(l, 2);
- }
- }
- lua_pop(l, 1);
- lua_pushstring(l, "options");
- lua_rawget(l, -2);
- if (lua_istable(l, -1)) {
- lua_pushstring(l, "interface");
- lua_rawget(l, -2);
- if (lua_isstring(l, -1)) {
- _nic = std::string(lua_tostring(l, -1));
- }
- lua_pop(l, 1);
- lua_pushstring(l, "verbose");
- lua_rawget(l, -2);
- if (lua_isboolean(l, -1)) {
- _verbose = lua_toboolean(l, -1);
- }
- lua_pop(l, 1);
- lua_pushstring(l, "proxy");
- lua_rawget(l, -2);
- if (lua_isstring(l, -1)) {
- _forceProxy = std::string(lua_tostring(l, -1));
- }
- lua_pop(l, 1);
- lua_pushstring(l, "manageCookies");
- lua_rawget(l, -2);
- if (lua_isboolean(l, -1)) {
- if (curl_version_number >= 0x074d00) _manageCookies = lua_toboolean(l, -1);
- }
- lua_pop(l, 1);
- }
- lua_end:
- lua_close(l);
- #endif
- }
- void BBS2chProxy5chPoster::makeSignature(BBS2chProxyHttpHeaders &headers, BBS2chProxyFormData &body)
- {
- bool isPink = _host.find("bbspink.com") != std::string::npos;
- bool shouldSign = appKey && (((api_mode & 2) && !isPink) || (api_mode & 4));
- bool shouldConvertBodyToUTF8 = (bbscgi_utf8 == 1 && shouldSign) || (bbscgi_utf8 == 2);
- _userAgentForRequest = headers.get("User-Agent");
- if (headers.has("X-MonaKey")) {
- _monaKeyForRequest = headers.get("X-MonaKey");
- }
- if (shouldConvertBodyToUTF8 && !headers.has("X-PostSig")) {
- if (convertBodyToUTF8(body)) {
- log_printf(1, "Converted request body to UTF-8: %s\n", body.toString().c_str());
- }
- else {
- log_printf(1, "Request body seems already to be UTF-8, will be sent without conversion\n");
- }
- std::string contentType = headers.get("Content-Type");
- std::transform(contentType.begin(), contentType.end(), contentType.begin(), tolower);
- if (contentType.find("charset=utf-8") == std::string::npos) {
- headers.set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
- log_printf(1, "Appended header \"Content-Type: application/x-www-form-urlencoded; charset=UTF-8\"\n");
- }
- }
- if (shouldSign && (!lua_script || !headers.has("X-PostSig"))) {
- if (!_userAgentForRequest.empty()) {
- _monaKeyForRequest = BBS2chProxyConnection::keyManager.getKey(_userAgentForRequest);
- appendPostSignature(body, _userAgentForRequest, _monaKeyForRequest, headers, false);
- } else {
- log_printf(0, "API: User-Agent muse be set explicitly to post with API.\n");
- }
- }
- if (!_monaKeyForRequest.empty()) {
- double wait = BBS2chProxyConnection::keyManager.secondsToWaitBeforePosting(_monaKeyForRequest);
- if (wait > 0) {
- log_printf(1, "Sleeping for %.1f seconds to avoid posting too fast...\n", wait);
- #ifdef _WIN32
- Sleep(wait * 1e+3);
- #else
- usleep(wait * 1e+6);
- #endif
- }
- }
- }
- long BBS2chProxy5chPoster::post()
- {
- CURL *curl = connectionDelegate->curl;
- long statusCode = 0;
- for (int run=0; run<2; run++) {
- BBS2chProxyHttpHeaders _headers = _requestHeaders;
- BBS2chProxyFormData _body = _requestBody;
- curl_slist *headersForCurl = NULL;
- _verbose = 0;
- _status = 0;
- _monaKeyForRequest.clear();
- _nic.clear();
- _forceProxy.clear();
- _isFirstRun = run == 0;
- _responseHeaders.clear();
- _isResponseChunked = false;
- _hasSetCookie = false;
- _manageCookies = manage_bbscgi_cookies;
- #ifdef USE_LUA
- if (lua_script) {
- runLuaScript(_headers, _body);
- }
- #endif
- makeSignature(_headers, _body);
- headersForCurl = prepareCurlHandle(_headers, _body, headersForCurl);
- curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback_bbscgi);
- curl_easy_setopt(curl, CURLOPT_HEADERDATA, this);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback_proxy);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
- CURLcode res = curl_easy_perform(curl);
- #if LIBCURL_VERSION_NUM >= 0x070e01 /* curl 7.14.1 or later */
- if (_manageCookies && _hasSetCookie) {
- appendCurlCookiesToJar(curl, BBS2chProxyConnection::keyManager.getCookieJar(_userAgentForRequest));
- }
- #endif
- if (res != CURLE_OK) {
- if (res == CURLE_WRITE_ERROR && _status == 1) {
- log_printf(1, "MonaKey should be reset. Sending the same request automatically...\n");
- curl_easy_reset(curl);
- curl_slist_free_all(headersForCurl);
- continue;
- }
- else if (res == CURLE_WRITE_ERROR && _status == 2) {
- log_printf(1, "Acorn cookie is rotten. Sending the same request automatically...\n");
- curl_easy_reset(curl);
- curl_slist_free_all(headersForCurl);
- continue;
- }
- else {
- log_printf(0, "curl error: %s (%s)\n", curl_easy_strerror(res), _url.c_str());
- if (!_status) connectionDelegate->socketToClient->sendResponse(503, "Service Unavailable");
- statusCode = 503;
- }
- }
- else {
- if (_isResponseChunked) {
- connectionDelegate->socketToClient->writeString("0\r\n\r\n");
- }
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &statusCode);
- }
- curl_easy_reset(curl);
- #if LIBCURL_VERSION_NUM >= 0x070e01 /* curl 7.14.1 or later */
- if (_manageCookies) {
- /* since curl_easy_reset() doesn't reset cookie engine, reset explicitly.
- curl < 7.77.0 doesn't have a way to disable cookie engine,
- so once enabled it will be enabled permanently. See https://github.com/curl/curl/issues/6889 */
- curl_easy_setopt(curl, CURLOPT_COOKIELIST, "ALL"); //force erase all cookies
- curl_easy_setopt(curl, CURLOPT_COOKIEFILE, NULL); //force disable cookie engine
- }
- #endif
- curl_slist_free_all(headersForCurl);
- break;
- }
- return statusCode;
- }
- void BBS2chProxyTalkPoster::makeSignature(BBS2chProxyHttpHeaders &headers, BBS2chProxyFormData &body)
- {
- bool shouldSign = appKey && (api_mode & 8);
- bool shouldConvertBodyToUTF8 = (bbscgi_utf8 == 1 && shouldSign) || (bbscgi_utf8 == 2);
- _userAgentForRequest = headers.get("User-Agent");
- if (headers.has("X-Write-Key")) {
- _monaKeyForRequest = headers.get("X-Write-Key");
- }
- if (shouldConvertBodyToUTF8 && !headers.has("X-Write-Token")) {
- if (convertBodyToUTF8(body)) {
- log_printf(1, "Converted request body to UTF-8: %s\n", body.toString().c_str());
- }
- else {
- log_printf(1, "Request body seems already to be UTF-8, will be sent without conversion\n");
- }
- std::string contentType = headers.get("Content-Type");
- std::transform(contentType.begin(), contentType.end(), contentType.begin(), tolower);
- if (contentType.find("charset=utf-8") == std::string::npos) {
- headers.set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
- log_printf(1, "Appended header \"Content-Type: application/x-www-form-urlencoded; charset=UTF-8\"\n");
- }
- }
- if (shouldSign && (!lua_script || !headers.has("X-Write-Token"))) {
- if (!_userAgentForRequest.empty()) {
- body.append("sid", BBS2chProxyConnection::auth.getSID());
- body.append("appkey", appKey);
- body.append("anonymous", body.has("subject") ? "true" : "false");
- _monaKeyForRequest = BBS2chProxyConnection::keyManager.getKey(_userAgentForRequest);
- appendPostSignature(body, _userAgentForRequest, _monaKeyForRequest, headers, true);
- } else {
- log_printf(0, "API: User-Agent muse be set explicitly to post with API.\n");
- }
- }
- if (!_monaKeyForRequest.empty()) {
- double wait = BBS2chProxyConnection::keyManager.secondsToWaitBeforePosting(_monaKeyForRequest);
- if (wait > 0) {
- log_printf(1, "Sleeping for %.1f seconds to avoid posting too fast...\n", wait);
- #ifdef _WIN32
- Sleep(wait * 1e+3);
- #else
- usleep(wait * 1e+6);
- #endif
- }
- }
- }
- long BBS2chProxyTalkPoster::post()
- {
- CURL *curl = connectionDelegate->curl;
- long statusCode = 0;
- for (int run=0; run<2; run++) {
- BBS2chProxyHttpHeaders _headers = _requestHeaders;
- BBS2chProxyFormData _body = _requestBody;
- curl_slist *headersForCurl = NULL;
- std::string acceptEncoding;
- _verbose = 0;
- _nic.clear();
- _forceProxy.clear();
- _manageCookies = false;
- #ifdef USE_LUA
- if (lua_script) {
- runLuaScript(_headers, _body);
- _manageCookies = false;
- }
- #endif
- makeSignature(_headers, _body);
- if (_headers.has("Accept-Encoding")) {
- acceptEncoding = _headers.get("Accept-Encoding");
- _headers.remove("Accept-Encoding");
- }
- headersForCurl = prepareCurlHandle(_headers, _body, headersForCurl);
- BBS2chProxyHttpHeaders receivedHeaders;
- std::vector<char> receivedBody;
- curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback_download);
- curl_easy_setopt(curl, CURLOPT_HEADERDATA, &receivedHeaders);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback_download);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, &receivedBody);
- if (!acceptEncoding.empty()) curl_easy_setopt(curl, CURLOPT_ENCODING, acceptEncoding.c_str());
- CURLcode res = curl_easy_perform(curl);
- bool responseSent = false;
- if (res == CURLE_OK) curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &statusCode);
- if (receivedHeaders.hasNameAndValue("Content-Type", "application/json")) {
- receivedBody.push_back('\0');
- JSON_Value *json = json_parse_string(&receivedBody.front());
- if (json && json_type(json) == JSONObject) {
- JSON_Object *root = json_object(json);
- const char *error = json_object_dotget_string(root, "error.message");
- if (error) {
- log_printf(0, "Posting to bbs.cgi has been cancelled. Reason: %s\n", error);
- std::string out = "<html>\n<head>\n<title>ERROR!</title>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=Shift_JIS\">\n</head>\n<body bgcolor=\"#EFEFEF\">\n<font size=\"+1\" color=\"#FF0000\"><b>ERROR: ";
- out += error;
- out += "</b></font>\n</body>\n</html>";
- char *outSJIS = convertUTF8ToShiftJIS(out.c_str(), out.size());
- connectionDelegate->socketToClient->sendBasicHeaders(200, "OK");
- connectionDelegate->socketToClient->writeString("Content-Type: text/html; charset=Shift_JIS\r\n\r\n");
- if (outSJIS) {
- connectionDelegate->socketToClient->write(outSJIS, strlen(outSJIS));
- free(outSJIS);
- }
- statusCode = 200;
- responseSent = true;
- } else if (statusCode == 200) {
- int resNum = json_object_get_number(root, "commentNumber");
- std::string out = "<html lang=\"ja\">\n<head>\n<title>書きこみました。</title>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=Shift_JIS\">\n</head>\n<body>書きこみが終わりました。<br><br>\n画面を切り替えるまでしばらくお待ち下さい。<br><br>\n</body>\n</html>";
- char *outSJIS = convertUTF8ToShiftJIS(out.c_str(), out.size());
- connectionDelegate->socketToClient->sendBasicHeaders(200, "OK");
- if (resNum) {
- std::ostringstream ss;
- ss << "X-Resnum: " << resNum << "\r\n";
- connectionDelegate->socketToClient->writeString(ss.str());
- }
- connectionDelegate->socketToClient->writeString("Content-Type: text/html; charset=Shift_JIS\r\n\r\n");
- if (outSJIS) {
- connectionDelegate->socketToClient->write(outSJIS, strlen(outSJIS));
- free(outSJIS);
- }
- responseSent = true;
- }
- }
- if (json) json_value_free(json);
- }
- else if (receivedHeaders.has("X-Write-Key")) {
- BBS2chProxyConnection::keyManager.setKey(receivedHeaders.get("X-Write-Key"), _monaKeyForRequest, _userAgentForRequest, 0);
- const std::string &extendToken = receivedHeaders.get("X-Write-Key-Extend-Token");
- if (run == 0) {
- log_printf(1, "MonaKey has been updated. Sending the same request automatically...\n");
- if (!extendToken.empty()) {
- _requestHeaders.set("X-Write-Key-Extend-Token", extendToken);
- }
- curl_easy_reset(curl);
- curl_slist_free_all(headersForCurl);
- continue;
- } else if (!extendToken.empty()) {
- log_printf(0, "WARNING: you must send header \"X-Write-Key-Extend-Token: %s\" to complete posting.\n", extendToken.c_str());
- }
- std::string out = "<html><head><title>■ 書き込み確認 ■</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=Shift_JIS\"></head><body bgcolor=\"#EEEEEE\"><font size=\"+1\" color=\"#FF0000\"><b>書きこみ&クッキー確認</b></font><br><br><b>投稿確認<br><b style=\"color: #F00; font-size: larger;\">この書き込みで本当にいいですか?<br>\n<form method=\"POST\" action=\"../test/bbs.cgi\" accept-charset=\"Shift_JIS\"><input type=hidden name=FROM value=><input type=hidden name=mail value=><input type=hidden name=MESSAGE value=><input type=hidden name=bbs value=><input type=hidden name=time value=><input type=hidden name=key value=><input type=submit value=\"上記全てを承諾して書き込む\" name=\"submit\"></form></body></html>";
- char *outSJIS = convertUTF8ToShiftJIS(out.c_str(), out.size());
- connectionDelegate->socketToClient->sendBasicHeaders(200, "OK");
- connectionDelegate->socketToClient->writeString("Content-Type: text/html; charset=Shift_JIS\r\n\r\n");
- if (outSJIS) {
- connectionDelegate->socketToClient->write(outSJIS, strlen(outSJIS));
- free(outSJIS);
- }
- statusCode = 200;
- responseSent = true;
- }
- if (!responseSent) {
- log_printf(5, "bbscgi response: %s\n", receivedHeaders.getStatusLine().c_str());
- for (BBS2chProxyHttpHeaders::iterator it = receivedHeaders.begin(); it != receivedHeaders.end(); ++it) {
- log_printf(5, "bbscgi response: %s\n", it->second.c_str());
- }
- receivedBody.push_back('\0');
- log_printf(5, "bbscgi response: %s\n", &receivedBody.front());
- connectionDelegate->socketToClient->sendResponse(503, "Service Unavailable");
- statusCode = 503;
- }
- curl_easy_reset(curl);
- curl_slist_free_all(headersForCurl);
- break;
- }
- return statusCode;
- }
- long BBS2chProxyTalkTo5chPoster::post()
- {
- CURL *curl = connectionDelegate->curl;
- long statusCode = 0;
- for (int run=0; run<2; run++) {
- BBS2chProxyHttpHeaders _headers = _requestHeaders;
- BBS2chProxyFormData _body = _requestBody;
- curl_slist *headersForCurl = NULL;
- _verbose = 0;
- _status = 0;
- _monaKeyForRequest = "";
- _nic.clear();
- _forceProxy.clear();
- _manageCookies = manage_bbscgi_cookies;
- #ifdef USE_LUA
- if (lua_script) {
- runLuaScript(_headers, _body);
- }
- #endif
- makeSignature(_headers, _body);
- headersForCurl = prepareCurlHandle(_headers, _body, headersForCurl);
- BBS2chProxyHttpHeaders receivedHeaders;
- curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback_download);
- curl_easy_setopt(curl, CURLOPT_HEADERDATA, &receivedHeaders);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback_download);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
- CURLcode res = curl_easy_perform(curl);
- if (res == CURLE_OK) {
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &statusCode);
- if (receivedHeaders.has("Set-Cookie")) {
- #if LIBCURL_VERSION_NUM >= 0x070e01 /* curl 7.14.1 or later */
- if (_manageCookies) {
- appendCurlCookiesToJar(curl, BBS2chProxyConnection::keyManager.getCookieJar(_userAgentForRequest));
- }
- #endif
- std::vector<std::string>& values = receivedHeaders.getEntry("Set-Cookie")->getValueList();
- for (std::vector<std::string>::iterator it = values.begin(); it != values.end(); it++) {
- std::string &value = *it;
- size_t start = value.find("domain=");
- if (start == std::string::npos) continue;
- start += 7;
- size_t end = value.find(";", start);
- size_t pos = value.find(".5ch.net", start);
- size_t domainLen = 8;
- if (pos == std::string::npos || (end != std::string::npos && pos >= end)) {
- pos = value.find(".bbspink.com", start);
- domainLen = 12;
- }
- if (pos != std::string::npos && (end == std::string::npos || pos < end)) {
- value.replace(start, pos+domainLen-start, ".talk-platform.com");
- }
- }
- }
- if (statusCode == 200 && !receivedHeaders.has("X-Chx-Error")) {
- std::ostringstream ss;
- ss << "{\"boardCode\":\"" << "5channel_" << _board << "\",\"threadNumber\":" << _thread << ",\"commentNumber\":" << receivedHeaders.get("X-Resnum") << "}";
- connectionDelegate->socketToClient->sendBasicHeaders(200, "OK");
- if (receivedHeaders.has("Set-Cookie")) connectionDelegate->socketToClient->writeString(receivedHeaders.getFull("Set-Cookie", true));
- connectionDelegate->socketToClient->writeString("Content-Type: application/json\r\n\r\n");
- connectionDelegate->socketToClient->writeString(ss.str());
- } else if (statusCode == 200) {
- const std::string &errorHeader = receivedHeaders.get("X-Chx-Error");
- if (_manageCookies && atoi(errorHeader.c_str()) == 1930) {
- log_printf(1, "Acorn cookie is rotten. Sending the same request automatically...\n");
- curl_easy_reset(curl);
- curl_slist_free_all(headersForCurl);
- continue;
- }
- std::ostringstream ss;
- ss << "{\"error\":{\"message\":\"" << errorHeader << "\"}}";
- connectionDelegate->socketToClient->sendBasicHeaders(200, "OK");
- if (receivedHeaders.has("Set-Cookie")) connectionDelegate->socketToClient->writeString(receivedHeaders.getFull("Set-Cookie", true));
- connectionDelegate->socketToClient->writeString("Content-Type: application/json\r\n\r\n");
- connectionDelegate->socketToClient->writeString(ss.str());
- } else {
- connectionDelegate->socketToClient->sendResponse(503, "Service Unavailable");
- statusCode = 503;
- }
- } else {
- connectionDelegate->socketToClient->sendResponse(503, "Service Unavailable");
- statusCode = 503;
- }
- curl_easy_reset(curl);
- curl_slist_free_all(headersForCurl);
- #if LIBCURL_VERSION_NUM >= 0x070e01 /* curl 7.14.1 or later */
- if (_manageCookies) {
- /* since curl_easy_reset() doesn't reset cookie engine, reset explicitly.
- curl < 7.77.0 doesn't have a way to disable cookie engine,
- so once enabled it will be enabled permanently. See https://github.com/curl/curl/issues/6889 */
- curl_easy_setopt(curl, CURLOPT_COOKIELIST, "ALL"); //force erase all cookies
- curl_easy_setopt(curl, CURLOPT_COOKIEFILE, NULL); //force disable cookie engine
- }
- #endif
- break;
- }
- return statusCode;
- }
|