diff options
Diffstat (limited to 'src/modules/netlib/netlibhttpproxy.cpp')
-rw-r--r-- | src/modules/netlib/netlibhttpproxy.cpp | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/src/modules/netlib/netlibhttpproxy.cpp b/src/modules/netlib/netlibhttpproxy.cpp new file mode 100644 index 0000000000..153d53660f --- /dev/null +++ b/src/modules/netlib/netlibhttpproxy.cpp @@ -0,0 +1,522 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2012 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+#include "netlib.h"
+
+typedef enum
+{
+ reqHelloGet,
+ reqOldGet,
+ reqOldPost,
+ reqNewPost,
+}
+RequestType;
+
+
+static int HttpGatewayReadSetResult(NetlibConnection *nlc, char *buf, int num, int peek)
+{
+ if (nlc->dataBufferLen == 0) return 0;
+
+ int bytes = min(num, nlc->dataBufferLen);
+ int rbytes = nlc->dataBufferLen - bytes;
+
+ memcpy(buf, nlc->dataBuffer, bytes);
+ if (!peek)
+ {
+ memmove(nlc->dataBuffer, nlc->dataBuffer + bytes, rbytes);
+ nlc->dataBufferLen = rbytes;
+ }
+
+ return bytes;
+}
+
+void HttpGatewayRemovePacket(NetlibConnection *nlc, int pck)
+{
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+ while (pck-- && nlc->pHttpProxyPacketQueue != NULL)
+ {
+ NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue;
+ nlc->pHttpProxyPacketQueue = nlc->pHttpProxyPacketQueue->next;
+
+ mir_free(p->dataBuffer);
+ mir_free(p);
+ }
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+}
+
+
+static bool NetlibHttpGatewaySend(struct NetlibConnection *nlc, RequestType reqType, const char *buf, int len)
+{
+ NETLIBHTTPREQUEST nlhrSend = {0};
+ char szUrl[512];
+
+ nlhrSend.cbSize = sizeof(nlhrSend);
+ nlhrSend.nlc = nlc;
+
+ nlhrSend.pData = (char*)buf;
+ nlhrSend.dataLength = len;
+
+ nlhrSend.flags = NLHRF_GENERATEHOST | NLHRF_DUMPPROXY | NLHRF_SMARTAUTHHEADER | NLHRF_NOPROXY | NLHRF_REDIRECT;
+ if (nlc->nlhpi.flags & NLHPIF_HTTP11) nlhrSend.flags |= NLHRF_HTTP11;
+
+ switch (reqType)
+ {
+ case reqHelloGet:
+ nlhrSend.requestType = REQUEST_GET;
+ nlhrSend.szUrl=nlc->nlu->user.szHttpGatewayHello;
+ break;
+
+ case reqOldGet:
+ nlhrSend.requestType = REQUEST_GET;
+ nlhrSend.timeout = -1;
+ if ((nlc->nlhpi.flags & NLHPIF_USEGETSEQUENCE) && (nlc->nlhpi.szHttpGetUrl != NULL))
+ {
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+
+ mir_snprintf(szUrl, SIZEOF(szUrl), "%s%u", nlc->nlhpi.szHttpGetUrl, nlc->nlhpi.firstGetSequence++);
+ if (nlc->nlhpi.flags & NLHPIF_GETPOSTSAMESEQUENCE) nlc->nlhpi.firstPostSequence++;
+
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+ nlhrSend.szUrl = szUrl;
+ }
+ else
+ nlhrSend.szUrl = nlc->nlhpi.szHttpGetUrl;
+ break;
+
+ case reqOldPost:
+ nlhrSend.requestType = REQUEST_POST;
+ if ((nlc->nlhpi.flags & NLHPIF_USEPOSTSEQUENCE) && (nlc->nlhpi.szHttpPostUrl != NULL))
+ {
+ mir_snprintf(szUrl, SIZEOF(szUrl), "%s%u", nlc->nlhpi.szHttpPostUrl, nlc->nlhpi.firstPostSequence);
+ nlhrSend.szUrl = szUrl;
+ }
+ else
+ nlhrSend.szUrl = nlc->nlhpi.szHttpPostUrl;
+ break;
+
+ case reqNewPost:
+ nlhrSend.requestType = REQUEST_POST;
+ nlhrSend.szUrl = nlc->nlhpi.szHttpPostUrl;
+ break;
+ }
+
+ if (nlc->usingDirectHttpGateway)
+ {
+ NETLIBOPENCONNECTION nloc;
+ NetlibConnFromUrl(nlhrSend.szUrl, false, nloc);
+
+ bool sameHost = lstrcmpA(nlc->nloc.szHost, nloc.szHost) == 0 && nlc->nloc.wPort == nloc.wPort;
+
+ if (!sameHost)
+ {
+ NetlibDoClose(nlc);
+
+ mir_free((char*)nlc->nloc.szHost);
+ nlc->nloc = nloc;
+ if (!NetlibDoConnect(nlc))
+ return false;
+ }
+ else
+ mir_free((char*)nloc.szHost);
+ }
+
+ nlhrSend.headersCount = 3;
+ nlhrSend.headers = (NETLIBHTTPHEADER*)alloca(sizeof(NETLIBHTTPHEADER) * nlhrSend.headersCount);
+ nlhrSend.headers[0].szName = "User-Agent";
+ nlhrSend.headers[0].szValue = nlc->nlu->user.szHttpGatewayUserAgent;
+ nlhrSend.headers[1].szName = "Cache-Control";
+ nlhrSend.headers[1].szValue = "no-cache, no-store ";
+ nlhrSend.headers[2].szName = "Pragma";
+ nlhrSend.headers[2].szValue = "no-cache";
+// nlhrSend.headers[3].szName = "Accept-Encoding";
+// nlhrSend.headers[3].szValue = "deflate, gzip";
+
+ return NetlibHttpSendRequest((WPARAM)nlc,(LPARAM)&nlhrSend) != SOCKET_ERROR;
+}
+
+static bool NetlibHttpGatewayStdPost(NetlibConnection *nlc, int& numPackets)
+{
+ int np = 0, len = 0;
+
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+
+ NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue;
+ while (p != NULL && np < nlc->nlhpi.combinePackets) { ++np; len += p->dataBufferLen; p = p->next;}
+
+ char *buf = (char*)alloca(len);
+
+ numPackets = np;
+ int dlen = 0;
+
+ p = nlc->pHttpProxyPacketQueue;
+ while (np--)
+ {
+ memcpy(buf + dlen, p->dataBuffer, p->dataBufferLen);
+ dlen += p->dataBufferLen;
+ p = p->next;
+ }
+
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+
+ return NetlibHttpGatewaySend(nlc, reqNewPost, buf, len);
+}
+
+static bool NetlibHttpGatewayOscarPost(NetlibConnection *nlc, const char *buf, int len, int flags)
+{
+ NETLIBHTTPREQUEST *nlhrReply = NULL;
+ NetlibConnection nlcSend = {0};
+
+ nlcSend.handleType = NLH_CONNECTION;
+ nlcSend.nlu = nlc->nlu;
+ nlcSend.nlhpi = nlc->nlhpi;
+ nlcSend.s = nlc->s2;
+ nlcSend.usingHttpGateway = nlc->usingHttpGateway;
+ nlcSend.szProxyServer = nlc->szProxyServer;
+ nlcSend.wProxyPort = nlc->wProxyPort;
+ nlcSend.proxyType = nlc->proxyType;
+
+ if (!NetlibReconnect(&nlcSend)) return false;
+ nlc->s2 = nlcSend.s;
+
+ nlcSend.hOkToCloseEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ NetlibInitializeNestedCS(&nlcSend.ncsRecv);
+ NetlibInitializeNestedCS(&nlcSend.ncsSend);
+
+ bool res = NetlibHttpGatewaySend(&nlcSend, reqOldPost, buf, len);
+ if (res)
+ {
+ NETLIBHTTPREQUEST *nlhrReply = NetlibHttpRecv(&nlcSend, flags | MSG_RAW | MSG_DUMPPROXY, MSG_RAW | MSG_DUMPPROXY);
+ if (nlhrReply != NULL)
+ {
+ if (nlhrReply->resultCode != 200)
+ {
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ res = false;
+ }
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ }
+ else
+ res = false;
+ }
+
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+
+ nlc->s2 = nlcSend.s;
+ mir_free((char*)nlcSend.nloc.szHost);
+
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+
+ nlc->nlhpi.firstPostSequence++;
+ if (nlc->nlhpi.flags & NLHPIF_GETPOSTSAMESEQUENCE) nlc->nlhpi.firstGetSequence++;
+
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+
+ return res;
+}
+
+ int NetlibHttpGatewayPost(struct NetlibConnection *nlc, const char *buf, int len, int flags)
+{
+ struct NetlibHTTPProxyPacketQueue *p;
+
+ if (nlc->nlhpi.szHttpGetUrl != NULL)
+ {
+ return NetlibHttpGatewayOscarPost(nlc, buf, len, flags) ? len : SOCKET_ERROR;
+ }
+
+ /*
+ * Gena01 - many changes here, do compare against the other version.
+ *
+ * Change #1: simplify to use similar code to GET
+ * Change #2: we need to allow to parse POST reply if szHttpGetUrl is NULL
+ * Change #3: Keep connection open if we need to.
+ *
+ * Impact: NONE! Since currently miranda doesn't allow szHttpGetUrl to be NULL, it will not connect
+ * with the new plugins that use this code.
+ */
+
+ p = ( NetlibHTTPProxyPacketQueue* )mir_alloc(sizeof(struct NetlibHTTPProxyPacketQueue));
+ p->dataBuffer = ( PBYTE )mir_alloc(len);
+ memcpy(p->dataBuffer, buf, len);
+ p->dataBufferLen = len;
+ p->next = NULL;
+
+ /*
+ * Now check to see where to insert this in our queue
+ */
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+ if (nlc->pHttpProxyPacketQueue == NULL)
+ {
+ nlc->pHttpProxyPacketQueue = p;
+ }
+ else
+ {
+ struct NetlibHTTPProxyPacketQueue *t = nlc->pHttpProxyPacketQueue;
+
+ while (t->next != NULL) t = t->next;
+ t->next = p;
+ }
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+
+ /*
+ * Gena01 - fake a Send!! tell 'em all is ok. We catch errors in Recv.
+ */
+ return len;
+}
+
+#define NETLIBHTTP_RETRYCOUNT 3
+#define NETLIBHTTP_RETRYTIMEOUT 2000
+
+int NetlibHttpGatewayRecv(struct NetlibConnection *nlc, char *buf, int len, int flags)
+{
+ bool peek = (flags & MSG_PEEK) != 0;
+
+ if (nlc->dataBufferLen != 0 && (!peek || nlc->dataBufferLen >= len))
+ {
+ return HttpGatewayReadSetResult(nlc, buf, len, peek);
+ }
+
+ for (int retryCount = 0; retryCount < NETLIBHTTP_RETRYCOUNT; )
+ {
+ if (nlc->nlhpi.szHttpGetUrl == NULL && retryCount == 0)
+ {
+ if (nlc->pollingTimeout == 0) nlc->pollingTimeout = 30;
+
+ /* We Need to sleep/wait for the data to send before we do receive */
+ for (int pollCount = nlc->pollingTimeout; pollCount--; )
+ {
+ if (nlc->pHttpProxyPacketQueue != NULL && GetTickCount() - nlc->lastPost > 1000)
+ break;
+
+ if (nlc->termRequested || (SleepEx(1000, TRUE) && Miranda_Terminated()))
+ return SOCKET_ERROR;
+ }
+
+ nlc->lastPost = GetTickCount();
+ if (nlc->pHttpProxyPacketQueue == NULL && nlc->nlu->user.pfnHttpGatewayWrapSend != NULL)
+ {
+ if (nlc->nlu->user.pfnHttpGatewayWrapSend(nlc, (PBYTE)"", 0, MSG_NOHTTPGATEWAYWRAP, NetlibSend) == SOCKET_ERROR)
+ return SOCKET_ERROR;
+ }
+ }
+
+ int numPackets = 0;
+ if (nlc->nlhpi.szHttpGetUrl)
+ {
+ if (!NetlibHttpGatewaySend(nlc, reqOldGet, NULL, 0))
+ {
+ if (GetLastError() == ERROR_ACCESS_DENIED || nlc->termRequested)
+ break;
+
+ ++retryCount;
+ continue;
+ }
+ }
+ else
+ {
+ if (!NetlibHttpGatewayStdPost(nlc, numPackets))
+ {
+ if (GetLastError() == ERROR_ACCESS_DENIED || nlc->termRequested)
+ break;
+
+ ++retryCount;
+ continue;
+ }
+ }
+ NETLIBHTTPREQUEST *nlhrReply = NetlibHttpRecv(nlc, flags | MSG_RAW | MSG_DUMPPROXY, MSG_RAW | MSG_DUMPPROXY);
+ if (nlhrReply == NULL) return SOCKET_ERROR;
+
+ if (nlc->nlu->user.pfnHttpGatewayUnwrapRecv && !(flags & MSG_NOHTTPGATEWAYWRAP))
+ {
+ nlhrReply->pData = (char*)nlc->nlu->user.pfnHttpGatewayUnwrapRecv(nlhrReply,
+ (PBYTE)nlhrReply->pData, nlhrReply->dataLength, &nlhrReply->dataLength, mir_realloc);
+/*
+ if (newBuffer == NULL)
+ {
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return SOCKET_ERROR;
+ }
+ else
+ nlhrReply->pData = (char*)newBuffer;
+*/
+ }
+
+ if (nlhrReply->resultCode >= 300)
+ {
+ int resultCode = nlhrReply->resultCode;
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+
+ if (nlc->nlhpi.szHttpGetUrl && resultCode != 404)
+ {
+ NetlibLogf(nlc->nlu, "Error received from proxy, retrying");
+ continue;
+ }
+ else
+ {
+ NetlibLogf(nlc->nlu, "Error received from proxy, retry attempts exceeded (%u)", retryCount);
+ SetLastError(ERROR_GEN_FAILURE);
+ return SOCKET_ERROR;
+ }
+ }
+ else
+ {
+ retryCount = 0;
+ HttpGatewayRemovePacket(nlc, numPackets);
+ }
+
+ if (nlhrReply->dataLength)
+ {
+ if (peek)
+ {
+ int rbytes = nlc->dataBufferLen + nlhrReply->dataLength;
+
+ nlc->dataBuffer = (PBYTE)mir_realloc(nlc->dataBuffer, rbytes);
+ memcpy(nlc->dataBuffer + nlc->dataBufferLen, nlhrReply->pData, nlhrReply->dataLength);
+ nlc->dataBufferLen = rbytes;
+
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+
+ return HttpGatewayReadSetResult(nlc, buf, len, peek);
+ }
+ else
+ {
+ int bytes = min(len, nlhrReply->dataLength);
+ int rbytes = nlhrReply->dataLength - bytes;
+
+ memcpy(buf, nlhrReply->pData, bytes);
+
+ nlc->dataBuffer = (PBYTE)mir_realloc(nlc->dataBuffer, rbytes);
+ if (rbytes) memcpy(nlc->dataBuffer, nlhrReply->pData + bytes, rbytes);
+ nlc->dataBufferLen = rbytes;
+
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return bytes;
+ }
+ }
+ else
+ {
+ if ((peek && nlc->dataBufferLen != 0) || nlhrReply->pData)
+ {
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return HttpGatewayReadSetResult(nlc, buf, len, peek);
+ }
+ }
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ }
+
+ SetLastError(ERROR_GEN_FAILURE);
+ return SOCKET_ERROR;
+}
+
+int NetlibInitHttpConnection(struct NetlibConnection *nlc, struct NetlibUser *nlu, NETLIBOPENCONNECTION *nloc)
+{
+ NETLIBHTTPREQUEST *nlhrReply = NULL;
+
+ nlc->nlhpi.firstGetSequence = 1;
+ nlc->nlhpi.firstPostSequence = 1;
+
+ if (nlu->user.szHttpGatewayHello != NULL)
+ {
+ nlc->usingHttpGateway = true;
+ if (NetlibHttpGatewaySend(nlc, reqHelloGet, NULL, 0))
+ nlhrReply = NetlibHttpRecv(nlc, MSG_DUMPPROXY | MSG_RAW, MSG_DUMPPROXY | MSG_RAW);
+ nlc->usingHttpGateway = false;
+ if (nlhrReply == NULL) return 0;
+
+ if (nlhrReply->resultCode != 200)
+ {
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return 0;
+ }
+ }
+ if (!nlu->user.pfnHttpGatewayInit(nlc, nloc, nlhrReply))
+ {
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return 0;
+ }
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+
+ /*
+ * Gena01 - Ok, we should be able to use just POST. Needed for Yahoo, NO GET requests
+ */
+ if(nlc->nlhpi.szHttpPostUrl == NULL)
+ {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+
+ nlc->usingHttpGateway = true;
+
+ //now properly connected
+ if (nlu->user.pfnHttpGatewayBegin && !nlu->user.pfnHttpGatewayBegin(nlc, nloc))
+ return 0;
+
+ return 1;
+}
+
+INT_PTR NetlibHttpGatewaySetInfo(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBHTTPPROXYINFO *nlhpi=(NETLIBHTTPPROXYINFO*)lParam;
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+
+ if (GetNetlibHandleType(nlc) != NLH_CONNECTION || nlhpi == NULL ||
+ nlhpi->cbSize < (sizeof(NETLIBHTTPPROXYINFO) - sizeof(int)) ||
+ nlhpi->szHttpPostUrl == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ mir_free(nlc->nlhpi.szHttpGetUrl);
+ mir_free(nlc->nlhpi.szHttpPostUrl);
+
+ nlc->nlhpi.combinePackets = 1;
+ memcpy(&nlc->nlhpi, nlhpi, min(nlhpi->cbSize, sizeof(*nlhpi)));
+ if (nlc->nlhpi.combinePackets == 0) nlc->nlhpi.combinePackets = 1;
+
+ nlc->nlhpi.szHttpGetUrl = mir_strdup(nlc->nlhpi.szHttpGetUrl);
+ nlc->nlhpi.szHttpPostUrl = mir_strdup(nlc->nlhpi.szHttpPostUrl);
+
+ return 1;
+}
+
+INT_PTR NetlibHttpSetSticky(WPARAM wParam, LPARAM lParam)
+{
+ struct NetlibUser * nu = (struct NetlibUser*)wParam;
+ if (GetNetlibHandleType(nu)!=NLH_USER) return ERROR_INVALID_PARAMETER;
+ mir_free(nu->szStickyHeaders);
+ nu->szStickyHeaders = mir_strdup((char*)lParam); // pointer is ours
+ return 0;
+}
+
+INT_PTR NetlibHttpSetPollingTimeout(WPARAM wParam, LPARAM lParam)
+{
+ int oldTimeout;
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ if (GetNetlibHandleType(nlc)!=NLH_CONNECTION) return -1;
+ oldTimeout = nlc->pollingTimeout;
+ nlc->pollingTimeout = lParam;
+ return oldTimeout;
+}
|