static NetlibConnection* NetlibHttpProcessUrl(NETLIBHTTPREQUEST *nlhr, NetlibUser *nlu, NetlibConnection *nlc, const char *szUrl = NULL) { NETLIBOPENCONNECTION nloc; if (szUrl == NULL) NetlibConnFromUrl(nlhr->szUrl, (nlhr->flags & NLHRF_SSL) != 0, nloc); else NetlibConnFromUrl(szUrl, false, nloc); nloc.flags |= NLOCF_HTTP; if (nloc.flags & NLOCF_SSL) nlhr->flags |= NLHRF_SSL; else nlhr->flags &= ~NLHRF_SSL; if (nlc != NULL) { bool httpProxy = !(nloc.flags & NLOCF_SSL) && nlc->proxyType == PROXYTYPE_HTTP; bool sameHost = mir_strcmp(nlc->nloc.szHost, nloc.szHost) == 0 && nlc->nloc.wPort == nloc.wPort; if (!httpProxy && !sameHost) { NetlibDoClose(nlc); mir_free((char*)nlc->nloc.szHost); nlc->nloc = nloc; return NetlibDoConnect(nlc) ? nlc : NULL; } } else nlc = (NetlibConnection*)NetlibOpenConnection((WPARAM)nlu, (LPARAM)&nloc); mir_free((char*)nloc.szHost); return nlc; }
bool NetlibReconnect(NetlibConnection *nlc) { char buf[4]; bool opened = nlc->s != INVALID_SOCKET; if (opened) { switch (WaitUntilReadable(nlc->s, 0, true)) { case SOCKET_ERROR: opened = false; break; case 0: opened = true; break; case 1: opened = recv(nlc->s, buf, 1, MSG_PEEK) > 0; break; } if (!opened) NetlibDoClose(nlc, true); } if (!opened) { if (Miranda_Terminated()) return false; if (nlc->usingHttpGateway) { nlc->proxyAuthNeeded = true; return my_connect(nlc, &nlc->nloc); } return NetlibDoConnect(nlc); } return true; }
static int NetlibHttpFallbackToDirect(NetlibConnection *nlc, NetlibUser *nlu, NETLIBOPENCONNECTION *nloc) { NetlibDoClose(nlc, true); NetlibLogf(nlu, "Fallback to direct connection"); nlc->proxyAuthNeeded = false; nlc->proxyType = 0; mir_free(nlc->szProxyServer); nlc->szProxyServer = NULL; if (!my_connect(nlc, nloc)) { NetlibLogf(nlu, "%s %d: %s() failed (%u)", __FILE__, __LINE__, "connect", WSAGetLastError()); return false; } return true; }
static int NetlibHttpFallbackToDirect(struct NetlibConnection *nlc, struct NetlibUser *nlu, NETLIBOPENCONNECTION *nloc) { NetlibDoClose(nlc, true); NetlibLogf(nlu,"Fallback to direct connection"); NetlibLogf(nlu,"(%p) Connecting to server %s:%d....", nlc, nloc->szHost, nloc->wPort); nlc->proxyAuthNeeded = false; nlc->proxyType = 0; mir_free(nlc->szProxyServer); nlc->szProxyServer = NULL; nlc->sinProxy.sin_family = AF_INET; nlc->sinProxy.sin_port = htons(nloc->wPort); nlc->sinProxy.sin_addr.S_un.S_addr = DnsLookup(nlu, nloc->szHost); if (nlc->sinProxy.sin_addr.S_un.S_addr == 0 || my_connect(nlc, nloc) == SOCKET_ERROR) { if (nlc->sinProxy.sin_addr.S_un.S_addr) NetlibLogf(nlu, "%s %d: %s() failed (%u)", __FILE__, __LINE__, "connect", WSAGetLastError()); return false; } return true; }
INT_PTR NetlibCloseHandle(WPARAM wParam, LPARAM) { switch(GetNetlibHandleType(wParam)) { case NLH_USER: { struct NetlibUser *nlu=(struct NetlibUser*)wParam; int i; EnterCriticalSection(&csNetlibUser); i = netlibUser.getIndex(nlu); if (i >= 0) netlibUser.remove(i); LeaveCriticalSection(&csNetlibUser); NetlibFreeUserSettingsStruct(&nlu->settings); mir_free(nlu->user.szSettingsModule); mir_free(nlu->user.szDescriptiveName); mir_free(nlu->user.szHttpGatewayHello); mir_free(nlu->user.szHttpGatewayUserAgent); mir_free(nlu->szStickyHeaders); break; } case NLH_CONNECTION: { struct NetlibConnection *nlc=(struct NetlibConnection*)wParam; HANDLE waitHandles[4]; DWORD waitResult; WaitForSingleObject(hConnectionHeaderMutex,INFINITE); if (nlc->usingHttpGateway) { HttpGatewayRemovePacket(nlc, -1); } else { if(nlc->s != INVALID_SOCKET) { NetlibDoClose(nlc); } if (nlc->s2 != INVALID_SOCKET) closesocket(nlc->s2); nlc->s2 = INVALID_SOCKET; } ReleaseMutex(hConnectionHeaderMutex); waitHandles[0]=hConnectionHeaderMutex; waitHandles[1]=nlc->hOkToCloseEvent; waitHandles[2]=nlc->ncsRecv.hMutex; waitHandles[3]=nlc->ncsSend.hMutex; waitResult=WaitForMultipleObjects( SIZEOF(waitHandles),waitHandles,TRUE,INFINITE); if(waitResult<WAIT_OBJECT_0 || waitResult >= WAIT_OBJECT_0 + SIZEOF(waitHandles)) { ReleaseMutex(hConnectionHeaderMutex); SetLastError(ERROR_INVALID_PARAMETER); //already been closed return 0; } nlc->handleType=0; mir_free(nlc->nlhpi.szHttpPostUrl); mir_free(nlc->nlhpi.szHttpGetUrl); mir_free(nlc->dataBuffer); mir_free((char*)nlc->nloc.szHost); mir_free(nlc->szNewUrl); mir_free(nlc->szProxyServer); NetlibDeleteNestedCS(&nlc->ncsRecv); NetlibDeleteNestedCS(&nlc->ncsSend); CloseHandle(nlc->hOkToCloseEvent); DeleteCriticalSection(&nlc->csHttpSequenceNums); ReleaseMutex(hConnectionHeaderMutex); NetlibLogf(nlc->nlu,"(%p:%u) Connection closed",nlc,nlc->s); break; } case NLH_BOUNDPORT: return NetlibFreeBoundPort((struct NetlibBoundPort*)wParam); case NLH_PACKETRECVER: { struct NetlibPacketRecver *nlpr=(struct NetlibPacketRecver*)wParam; mir_free(nlpr->packetRecver.buffer); break; } default: SetLastError(ERROR_INVALID_PARAMETER); return 0; } mir_free((void*)wParam); return 1; }
NETLIBHTTPREQUEST* NetlibHttpRecv(NetlibConnection *nlc, DWORD hflags, DWORD dflags, bool isConnect) { int dataLen = -1, i, chunkhdr = 0; bool chunked = false; int cenc = 0, cenctype = 0, close = 0; next: NETLIBHTTPREQUEST *nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags); if (nlhrReply == NULL) return NULL; if (nlhrReply->resultCode == 100) { NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply); goto next; } for (i = 0; i < nlhrReply->headersCount; i++) { NETLIBHTTPHEADER &p = nlhrReply->headers[i]; if (!mir_strcmpi(p.szName, "Content-Length")) dataLen = atoi(p.szValue); if (!mir_strcmpi(p.szName, "Content-Encoding")) { cenc = i; if (strstr(p.szValue, "gzip")) cenctype = 1; else if (strstr(p.szValue, "deflate")) cenctype = 2; } if (!mir_strcmpi(p.szName, "Connection")) close = !mir_strcmpi(p.szValue, "close"); if (!mir_strcmpi(p.szName, "Transfer-Encoding") && !mir_strcmpi(p.szValue, "chunked")) { chunked = true; chunkhdr = i; dataLen = -1; } } if (nlhrReply->resultCode >= 200 && (dataLen > 0 || (!isConnect && dataLen < 0))) { int recvResult, chunksz = -1; int dataBufferAlloced; if (chunked) { chunksz = NetlibHttpRecvChunkHeader(nlc, true, dflags); if (chunksz == SOCKET_ERROR) { NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply); return NULL; } dataLen = chunksz; } dataBufferAlloced = dataLen < 0 ? 2048 : dataLen + 1; nlhrReply->pData = (char*)mir_realloc(nlhrReply->pData, dataBufferAlloced); while (chunksz != 0) { while (true) { recvResult = RecvWithTimeoutTime(nlc, GetTickCount() + HTTPRECVDATATIMEOUT, nlhrReply->pData + nlhrReply->dataLength, dataBufferAlloced - nlhrReply->dataLength - 1, dflags | (cenctype ? MSG_NODUMP : 0)); if (recvResult == 0) break; if (recvResult == SOCKET_ERROR) { NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply); return NULL; } nlhrReply->dataLength += recvResult; if (dataLen >= 0) { if (nlhrReply->dataLength >= dataLen) break; } else if ((dataBufferAlloced - nlhrReply->dataLength) < 256) { dataBufferAlloced += 2048; nlhrReply->pData = (char*)mir_realloc(nlhrReply->pData, dataBufferAlloced); if (nlhrReply->pData == NULL) { SetLastError(ERROR_OUTOFMEMORY); NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply); return NULL; } } Sleep(10); } if (!chunked) break; chunksz = NetlibHttpRecvChunkHeader(nlc, false, dflags); if (chunksz == SOCKET_ERROR) { NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply); return NULL; } dataLen += chunksz; dataBufferAlloced += chunksz; nlhrReply->pData = (char*)mir_realloc(nlhrReply->pData, dataBufferAlloced); } nlhrReply->pData[nlhrReply->dataLength] = '\0'; } if (chunked) { nlhrReply->headers[chunkhdr].szName = (char*)mir_realloc(nlhrReply->headers[chunkhdr].szName, 16); mir_strcpy(nlhrReply->headers[chunkhdr].szName, "Content-Length"); nlhrReply->headers[chunkhdr].szValue = (char*)mir_realloc(nlhrReply->headers[chunkhdr].szValue, 16); mir_snprintf(nlhrReply->headers[chunkhdr].szValue, 16, "%u", nlhrReply->dataLength); } if (cenctype) { int bufsz = nlhrReply->dataLength; char* szData = NULL; switch (cenctype) { case 1: szData = gzip_decode(nlhrReply->pData, &bufsz, 0x10 | MAX_WBITS); break; case 2: szData = gzip_decode(nlhrReply->pData, &bufsz, -MAX_WBITS); if (bufsz < 0) { bufsz = nlhrReply->dataLength; szData = gzip_decode(nlhrReply->pData, &bufsz, MAX_WBITS); } break; } if (bufsz > 0) { NetlibDumpData(nlc, (PBYTE)szData, bufsz, 0, dflags); mir_free(nlhrReply->pData); nlhrReply->pData = szData; nlhrReply->dataLength = bufsz; mir_free(nlhrReply->headers[cenc].szName); mir_free(nlhrReply->headers[cenc].szValue); memmove(&nlhrReply->headers[cenc], &nlhrReply->headers[cenc+1], (--nlhrReply->headersCount-cenc)*sizeof(nlhrReply->headers[0])); } else if (bufsz == 0) { mir_free(nlhrReply->pData); nlhrReply->pData = NULL; nlhrReply->dataLength = 0; } } if (close && (nlc->proxyType != PROXYTYPE_HTTP || nlc->nloc.flags & NLOCF_SSL) && (!isConnect || nlhrReply->resultCode != 200)) NetlibDoClose(nlc); return nlhrReply; }
static bool NetlibHttpGatewaySend(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)) { mir_cslock lck(nlc->csHttpSequenceNums); mir_snprintf(szUrl, SIZEOF(szUrl), "%s%u", nlc->nlhpi.szHttpGetUrl, nlc->nlhpi.firstGetSequence++); if (nlc->nlhpi.flags & NLHPIF_GETPOSTSAMESEQUENCE) nlc->nlhpi.firstPostSequence++; 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; }