static int NetlibHttpRecvChunkHeader(NetlibConnection *nlc, bool first, DWORD flags) { char data[1000]; while (true) { int recvResult = NLRecv(nlc, data, _countof(data)-1, MSG_RAW | MSG_PEEK); if (recvResult <= 0 || recvResult >= _countof(data)) return SOCKET_ERROR; data[recvResult] = 0; char *peol1 = strchr(data, '\n'); if (peol1 == NULL) continue; char *peol2 = first ? peol1 : strchr(peol1 + 1, '\n'); if (peol2 == NULL) continue; int sz = peol2 - data + 1; int r = strtol(first ? data : peol1 + 1, NULL, 16); if (r == 0) { char *peol3 = strchr(peol2 + 1, '\n'); if (peol3 == NULL) continue; sz = peol3 - data + 1; } NLRecv(nlc, data, sz, MSG_RAW | flags); return r; } }
bool RecvUntilTimeout(NetlibConnection *nlc, char *buf, int len, int flags, DWORD dwTimeout) { int nReceived = 0; DWORD dwTimeNow, dwCompleteTime = GetTickCount() + dwTimeout; while ((dwTimeNow = GetTickCount()) < dwCompleteTime) { if (WaitUntilReadable(nlc->s, dwCompleteTime - dwTimeNow) <= 0) return false; nReceived = NLRecv(nlc, buf, len, flags); if (nReceived <= 0) return false; buf += nReceived; len -= nReceived; if (len <= 0) return true; } SetLastError(ERROR_TIMEOUT); return false; }
INT_PTR NetlibPacketRecverGetMore(WPARAM wParam, LPARAM lParam) { struct NetlibPacketRecver *nlpr = (struct NetlibPacketRecver*)wParam; NETLIBPACKETRECVER *nlprParam = (NETLIBPACKETRECVER*)lParam; if (GetNetlibHandleType(nlpr) != NLH_PACKETRECVER || nlprParam == NULL || nlprParam->cbSize != sizeof(NETLIBPACKETRECVER) || nlprParam->bytesUsed > nlpr->packetRecver.bytesAvailable) { SetLastError(ERROR_INVALID_PARAMETER); return SOCKET_ERROR; } if (Miranda_Terminated()) { /* HACK: Lame, break while loops of protocols that can't kill their while loops, (cough, ICQ, cough) */ SetLastError(ERROR_TIMEOUT); return SOCKET_ERROR; } nlpr->packetRecver.dwTimeout = nlprParam->dwTimeout; if (nlprParam->bytesUsed == 0) { if (nlpr->packetRecver.bytesAvailable == nlpr->packetRecver.bufferSize) { nlpr->packetRecver.bytesAvailable = 0; NetlibLogf(nlpr->nlc->nlu, "Packet recver: packet overflowed buffer, ditching"); } } else { MoveMemory(nlpr->packetRecver.buffer, nlpr->packetRecver.buffer + nlprParam->bytesUsed, nlpr->packetRecver.bytesAvailable - nlprParam->bytesUsed); nlpr->packetRecver.bytesAvailable -= nlprParam->bytesUsed; } if (nlprParam->dwTimeout != INFINITE) { if (!si.pending(nlpr->nlc->hSsl) && WaitUntilReadable(nlpr->nlc->s, nlprParam->dwTimeout) <= 0) { *nlprParam = nlpr->packetRecver; return SOCKET_ERROR; } } INT_PTR recvResult = NLRecv(nlpr->nlc, (char*)nlpr->packetRecver.buffer + nlpr->packetRecver.bytesAvailable, nlpr->packetRecver.bufferSize - nlpr->packetRecver.bytesAvailable, 0); if (recvResult > 0) nlpr->packetRecver.bytesAvailable += recvResult; *nlprParam = nlpr->packetRecver; return recvResult; }
INT_PTR NetlibHttpRecvHeaders(WPARAM wParam, LPARAM lParam) { NetlibConnection *nlc = (struct NetlibConnection*)wParam; if (!NetlibEnterNestedCS(nlc, NLNCS_RECV)) return 0; char *peol, *pbuffer; int headersCount = 0, bufferSize = 8192; DWORD dwRequestTimeoutTime = GetTickCount() + HTTPRECVDATATIMEOUT; NETLIBHTTPREQUEST *nlhr = (NETLIBHTTPREQUEST*)mir_calloc(sizeof(NETLIBHTTPREQUEST)); nlhr->cbSize = sizeof(NETLIBHTTPREQUEST); nlhr->nlc = nlc; // Needed to id connection in the protocol HTTP gateway wrapper functions nlhr->requestType = REQUEST_RESPONSE; int firstLineLength = 0; if (!HttpPeekFirstResponseLine(nlc, dwRequestTimeoutTime, lParam | MSG_PEEK, &nlhr->resultCode, &nlhr->szResultDescr, &firstLineLength)) { NetlibLeaveNestedCS(&nlc->ncsRecv); NetlibHttpFreeRequestStruct(0, (LPARAM)nlhr); return 0; } char *buffer = (char*)mir_alloc(bufferSize + 1); int bytesPeeked = NLRecv(nlc, buffer, min(firstLineLength, bufferSize), lParam | MSG_DUMPASTEXT); if (bytesPeeked != firstLineLength) { NetlibLeaveNestedCS(&nlc->ncsRecv); NetlibHttpFreeRequestStruct(0, (LPARAM)nlhr); if (bytesPeeked != SOCKET_ERROR) SetLastError(ERROR_HANDLE_EOF); mir_free(buffer); return 0; } // Make sure all headers arrived bytesPeeked = 0; for (bool headersCompleted = false; !headersCompleted;) { if (bytesPeeked >= bufferSize) { bufferSize += 8192; mir_free(buffer); if (bufferSize > 32 * 1024) { bytesPeeked = 0; break; } buffer = (char*)mir_alloc(bufferSize + 1); } bytesPeeked = RecvWithTimeoutTime(nlc, dwRequestTimeoutTime, buffer, bufferSize, MSG_PEEK | MSG_NODUMP | lParam); if (bytesPeeked == 0) break; if (bytesPeeked == SOCKET_ERROR) { bytesPeeked = 0; break; } buffer[bytesPeeked] = 0; for (pbuffer = buffer, headersCount = 0;; pbuffer = peol + 1, ++headersCount) { peol = strchr(pbuffer, '\n'); if (peol == NULL) break; if (peol == pbuffer || (peol == (pbuffer + 1) && *pbuffer == '\r')) { bytesPeeked = peol - buffer + 1; headersCompleted = true; break; } } } // Receive headers if (bytesPeeked > 0) bytesPeeked = NLRecv(nlc, buffer, bytesPeeked, lParam | MSG_DUMPASTEXT); if (bytesPeeked <= 0) { NetlibLeaveNestedCS(&nlc->ncsRecv); NetlibHttpFreeRequestStruct(0, (LPARAM)nlhr); mir_free(buffer); return 0; } buffer[bytesPeeked] = 0; nlhr->headersCount = headersCount; nlhr->headers = (NETLIBHTTPHEADER*)mir_calloc(sizeof(NETLIBHTTPHEADER) * headersCount); for (pbuffer = buffer, headersCount = 0;; pbuffer = peol + 1, ++headersCount) { peol = strchr(pbuffer, '\n'); if (peol == NULL || peol == pbuffer || (peol == (pbuffer + 1) && *pbuffer == '\r')) break; *peol = 0; char *pColon = strchr(pbuffer, ':'); if (pColon == NULL) { NetlibHttpFreeRequestStruct(0, (LPARAM)nlhr); nlhr = NULL; SetLastError(ERROR_INVALID_DATA); break; } *(pColon++) = 0; nlhr->headers[headersCount].szName = mir_strdup(rtrim(pbuffer)); nlhr->headers[headersCount].szValue = mir_strdup(lrtrimp(pColon)); } NetlibLeaveNestedCS(&nlc->ncsRecv); mir_free(buffer); return (INT_PTR)nlhr; }