char* MimeHeaders::readFromBuffer(char* src) { clear(); while (*src) { char* peol = strchr(src, '\n'); if (peol == NULL) return strchr(src, 0); else if (peol == src) return src + 1; else if (peol == (src + 1) && *src == '\r') return src + 2; *peol = 0; char* delim = strchr(src, ':'); if (delim) { *delim = 0; MimeHeader& H = mVals[allocSlot()]; H.name = lrtrimp(src); H.value = lrtrimp(delim + 1); H.flags = 0; } src = peol + 1; } return src; }
static int HttpPeekFirstResponseLine(NetlibConnection *nlc, DWORD dwTimeoutTime, DWORD recvFlags, int *resultCode, char **ppszResultDescr, int *length) { int bytesPeeked; char buffer[2048]; char *peol; while (true) { bytesPeeked = RecvWithTimeoutTime(nlc, dwTimeoutTime, buffer, _countof(buffer) - 1, MSG_PEEK | recvFlags); if (bytesPeeked == 0) { SetLastError(ERROR_HANDLE_EOF); return 0; } if (bytesPeeked == SOCKET_ERROR) return 0; buffer[bytesPeeked] = '\0'; if ((peol = strchr(buffer, '\n')) != NULL) break; if ((int)mir_strlen(buffer) < bytesPeeked) { SetLastError(ERROR_BAD_FORMAT); return 0; } if (bytesPeeked == _countof(buffer) - 1) { SetLastError(ERROR_BUFFER_OVERFLOW); return 0; } if (Miranda_Terminated()) return 0; Sleep(10); } if (peol == buffer) { SetLastError(ERROR_BAD_FORMAT); return 0; } *peol = '\0'; if (_strnicmp(buffer, "HTTP/", 5)) { SetLastError(ERROR_BAD_FORMAT); return 0; } size_t off = strcspn(buffer, " \t"); if (off >= (unsigned)bytesPeeked) return 0; char* pResultCode = buffer + off; *(pResultCode++) = 0; char* pResultDescr; *resultCode = strtol(pResultCode, &pResultDescr, 10); if (ppszResultDescr) *ppszResultDescr = mir_strdup(lrtrimp(pResultDescr)); if (length) *length = peol - buffer + 1; return 1; }
static void discoverUPnP(void) { char* buf; int buflen; unsigned i, j, nip = 0; unsigned* ips = NULL; static const unsigned any = INADDR_ANY; static const TIMEVAL tv = { 1, 600000 }; char szUrl[256] = ""; char hostname[256]; PHOSTENT he; fd_set readfd; SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); SOCKADDR_IN enetaddr; enetaddr.sin_family = AF_INET; enetaddr.sin_port = htons(1900); enetaddr.sin_addr.s_addr = inet_addr("239.255.255.250"); gethostname(hostname, sizeof(hostname)); he = gethostbyname(hostname); if (he) { while (he->h_addr_list[nip]) ++nip; ips = (unsigned*)mir_alloc(nip * sizeof(unsigned)); for (j = 0; j < nip; j++) ips[j] = *(unsigned*)he->h_addr_list[j]; } buf = (char*)mir_alloc(1500); for (i = 3; --i && szUrl[0] == 0;) { for (j = 0; j < nip; j++) { if (ips) setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&ips[j], sizeof(unsigned)); buflen = mir_snprintf(buf, 1500, search_request_msg, "WANIPConnection:1"); sendto(sock, buf, buflen, 0, (SOCKADDR*)&enetaddr, sizeof(enetaddr)); LongLog(buf); buflen = mir_snprintf(buf, 1500, search_request_msg, "WANPPPConnection:1"); sendto(sock, buf, buflen, 0, (SOCKADDR*)&enetaddr, sizeof(enetaddr)); LongLog(buf); } if (Miranda_Terminated()) break; FD_ZERO(&readfd); FD_SET(sock, &readfd); while (select(1, &readfd, NULL, NULL, &tv) >= 1) { buflen = recv(sock, buf, 1500, 0); if (buflen != SOCKET_ERROR) { buf[buflen] = 0; LongLog(buf); if (txtParseParam(buf, NULL, "LOCATION:", "\n", szUrl, sizeof(szUrl)) || txtParseParam(buf, NULL, "Location:", "\n", szUrl, sizeof(szUrl))) { char age[30]; char szHostNew[256], szHostExist[256]; lrtrim(szUrl); parseURL(szUrl, szHostNew, NULL, NULL); parseURL(szCtlUrl, szHostExist, NULL, NULL); if (mir_strcmp(szHostNew, szHostExist) == 0) { gatewayFound = true; break; } txtParseParam(buf, NULL, "ST:", "\n", szDev, sizeof(szDev)); txtParseParam(buf, "max-age", " = ", "\n", age, sizeof(age)); expireTime = atoi(lrtrimp(age)); lrtrim(szDev); if (getUPnPURLs(szUrl, sizeof(szUrl))) { gatewayFound = getExtIP() != 0; if (gatewayFound) break; } } } FD_ZERO(&readfd); FD_SET(sock, &readfd); } } mir_free(buf); mir_free(ips); setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&any, sizeof(unsigned)); closesocket(sock); }
static int httpTransact(char* szUrl, char* szResult, int resSize, char* szActionName, ReqType reqtype) { // Parse URL char szHost[256], szPath[256], szRes[16]; int sz = 0, res = 0; unsigned short sPort; bool needClose = false; const char* szPostHdr = soap_post_hdr; char* szData = (char*)mir_alloc(4096); char* szReq = NULL; parseURL(szUrl, szHost, &sPort, szPath); if (sPort != sConnPort || _stricmp(szHost, szConnHost)) closeRouterConnection(); else validateSocket(); while (true) { retryCount = 0; switch (reqtype) { case DeviceGetReq: sz = mir_snprintf(szData, 4096, xml_get_hdr, szPath, szHost, sPort); break; case ControlAction: { char szData1[1024]; szReq = mir_strdup(szResult); sz = mir_snprintf(szData1, _countof(szData1), soap_action, szActionName, szDev, szReq, szActionName); sz = mir_snprintf(szData, 4096, szPostHdr, szPath, szHost, sPort, sz, szDev, szActionName, szData1); } break; case ControlQuery: { char szData1[1024]; sz = mir_snprintf(szData1, _countof(szData1), soap_query, szActionName); sz = mir_snprintf(szData, 4096, szPostHdr, szPath, szHost, sPort, sz, "urn:schemas-upnp-org:control-1-0", "QueryStateVariable", szData1); } break; } szResult[0] = 0; { static const TIMEVAL tv = { 6, 0 }; static unsigned ttl = 4; static u_long mode = 1; fd_set rfd, wfd, efd; SOCKADDR_IN enetaddr; retrycon: if (sock == INVALID_SOCKET) { sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); enetaddr.sin_family = AF_INET; enetaddr.sin_port = htons(sPort); enetaddr.sin_addr.s_addr = inet_addr(szHost); // Resolve host name if needed if (enetaddr.sin_addr.s_addr == INADDR_NONE) { PHOSTENT he = gethostbyname(szHost); if (he) enetaddr.sin_addr.s_addr = *(unsigned*)he->h_addr_list[0]; } NetlibLogf(NULL, "UPnP HTTP connection Host: %s Port: %u", szHost, sPort); FD_ZERO(&rfd); FD_ZERO(&wfd); FD_ZERO(&efd); FD_SET(sock, &rfd); FD_SET(sock, &wfd); FD_SET(sock, &efd); // Limit the scope of the connection (does not work for setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(unsigned)); // Put socket into non-blocking mode for timeout on connect ioctlsocket(sock, FIONBIO, &mode); // Connect to the remote host if (connect(sock, (SOCKADDR*)&enetaddr, sizeof(enetaddr)) == SOCKET_ERROR) { int err = WSAGetLastError(); // Socket connection failed if (err != WSAEWOULDBLOCK) { closeRouterConnection(); NetlibLogf(NULL, "UPnP connect failed %d", err); break; } // Wait for socket to connect else if (select(1, &rfd, &wfd, &efd, &tv) != 1) { closeRouterConnection(); NetlibLogf(NULL, "UPnP connect timeout"); break; } else if (!FD_ISSET(sock, &wfd)) { closeRouterConnection(); NetlibLogf(NULL, "UPnP connect failed"); break; } } strncpy_s(szConnHost, szHost, _TRUNCATE); sConnPort = sPort; } if (send(sock, szData, sz, 0) != SOCKET_ERROR) { char *hdrend = NULL; int acksz = 0, pktsz = 0; if (szActionName == NULL) { int len = sizeof(locIP); getsockname(sock, (SOCKADDR*)&locIP, &len); if (locIP.sin_addr.S_un.S_addr == 0x0100007f) { struct hostent *he; gethostname(szPath, sizeof(szPath)); he = gethostbyname(szPath); if (he != NULL) locIP.sin_addr.S_un.S_addr = *(PDWORD)he->h_addr_list[0]; } } LongLog(szData); sz = 0; while (true) { int bytesRecv; FD_ZERO(&rfd); FD_SET(sock, &rfd); // Wait for the next packet if (select(1, &rfd, NULL, NULL, &tv) != 1) { closeRouterConnection(); NetlibLogf(NULL, "UPnP recieve timeout"); break; } // bytesRecv = recv(sock, &szResult[sz], resSize - sz, 0); // Connection closed or aborted, all data received if (bytesRecv == 0 || bytesRecv == SOCKET_ERROR) { closeRouterConnection(); if ((bytesRecv == SOCKET_ERROR || sz == 0) && retryCount < 2) { ++retryCount; goto retrycon; } break; } sz += bytesRecv; // Insert null terminator to use string functions if (sz >= (resSize - 1)) { szResult[resSize - 1] = 0; break; } else szResult[sz] = 0; // HTTP header found? if (hdrend == NULL) { // Find HTTP header end hdrend = strstr(szResult, "\r\n\r\n"); if (hdrend == NULL) { hdrend = strstr(szResult, "\n\n"); if (hdrend) hdrend += 2; } else hdrend += 4; if (hdrend != NULL) { // Get packet size if provided if (txtParseParam(szResult, NULL, "Content-Length:", "\n", szRes, sizeof(szRes)) || txtParseParam(szResult, NULL, "CONTENT-LENGTH:", "\n", szRes, sizeof(szRes))) { // Add size of HTTP header to the packet size to compute full transmission size pktsz = atol(ltrimp(szRes)) + (hdrend - szResult); } // Get encoding type if provided else if (txtParseParam(szResult, NULL, "Transfer-Encoding:", "\n", szRes, sizeof(szRes))) { if (_stricmp(lrtrimp(szRes), "Chunked") == 0) acksz = hdrend - szResult; } if (txtParseParam(szResult, NULL, "Connection:", "\n", szRes, sizeof(szRes))) { needClose = (_stricmp(lrtrimp(szRes), "close") == 0); } } } // Content-Length bytes reached, all data received if (sz >= pktsz && pktsz != 0) { szResult[pktsz] = 0; break; } // Chunked encoding processing if (sz > acksz && acksz != 0) { retry: // Parse out chunk size char* data = szResult + acksz; char* peol1 = data == hdrend ? data - 1 : strchr(data, '\n'); if (peol1 != NULL) { char *peol2 = strchr(++peol1, '\n'); if (peol2 != NULL) { // Get chunk size int chunkBytes = strtol(peol1, NULL, 16); acksz += chunkBytes; peol2++; memmove(data, peol2, mir_strlen(peol2) + 1); sz -= peol2 - data; // Last chunk, all data received if (chunkBytes == 0) break; if (sz > acksz) goto retry; } } } } LongLog(szResult); } else { if (retryCount < 2) { closeRouterConnection(); ++retryCount; goto retrycon; } else NetlibLogf(NULL, "UPnP send failed %d", WSAGetLastError()); } } txtParseParam(szResult, "HTTP", " ", " ", szRes, sizeof(szRes)); res = atol(szRes); if (szActionName != NULL && res == 405 && szPostHdr == soap_post_hdr) szPostHdr = soap_post_hdr_m; else break; } if (needClose) closeRouterConnection(); mir_free(szData); mir_free(szReq); return res; }
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; }
INT_PTR NetlibHttpSendRequest(WPARAM wParam, LPARAM lParam) { NetlibConnection *nlc = (struct NetlibConnection*)wParam; NETLIBHTTPREQUEST *nlhr = (NETLIBHTTPREQUEST*)lParam; NETLIBHTTPREQUEST *nlhrReply = NULL; HttpSecurityContext httpSecurity; struct ResizableCharBuffer httpRequest = { 0 }; char *szHost = NULL, *szNewUrl = NULL; char *pszProxyAuthHdr = NULL, *pszAuthHdr = NULL; int i, doneHostHeader, doneContentLengthHeader, doneProxyAuthHeader, doneAuthHeader; int bytesSent = 0; bool lastFirstLineFail = false; if (nlhr == NULL || nlhr->cbSize != sizeof(NETLIBHTTPREQUEST) || nlhr->szUrl == NULL || nlhr->szUrl[0] == '\0') { SetLastError(ERROR_INVALID_PARAMETER); return SOCKET_ERROR; } NetlibUser *nlu = nlc->nlu; if (GetNetlibHandleType(nlu) != NLH_USER) { SetLastError(ERROR_INVALID_PARAMETER); return SOCKET_ERROR; } int hdrTimeout = (nlhr->timeout) ? nlhr->timeout : HTTPRECVHEADERSTIMEOUT; const char *pszRequest; switch (nlhr->requestType) { case REQUEST_GET: pszRequest = "GET"; break; case REQUEST_POST: pszRequest = "POST"; break; case REQUEST_CONNECT: pszRequest = "CONNECT"; break; case REQUEST_HEAD: pszRequest = "HEAD"; break; case REQUEST_PUT: pszRequest = "PUT"; break; case REQUEST_DELETE: pszRequest = "DELETE"; break; default: SetLastError(ERROR_INVALID_PARAMETER); return SOCKET_ERROR; } if (!nlc->usingHttpGateway) if (!NetlibEnterNestedCS(nlc, NLNCS_SEND)) return SOCKET_ERROR; const char *pszFullUrl = nlhr->szUrl; const char *pszUrl = NULL; unsigned complete = false; int count = 11; while (--count) { if (GetNetlibHandleType(nlc) != NLH_CONNECTION) { nlc = NULL; bytesSent = SOCKET_ERROR; break; } if (!NetlibReconnect(nlc)) { bytesSent = SOCKET_ERROR; break; } if (!pszUrl) { pszUrl = pszFullUrl; if (nlhr->flags & (NLHRF_SMARTREMOVEHOST | NLHRF_REMOVEHOST | NLHRF_GENERATEHOST)) { bool usingProxy = nlc->proxyType == PROXYTYPE_HTTP && !(nlhr->flags & NLHRF_SSL); mir_free(szHost); szHost = NULL; const char *ppath, *phost; phost = strstr(pszUrl, "://"); if (phost == NULL) phost = pszUrl; else phost += 3; ppath = strchr(phost, '/'); if (ppath == phost) phost = NULL; if (nlhr->flags & NLHRF_GENERATEHOST) { szHost = mir_strdup(phost); if (ppath && phost) szHost[ppath - phost] = 0; } if (nlhr->flags & NLHRF_REMOVEHOST || (nlhr->flags & NLHRF_SMARTREMOVEHOST && !usingProxy)) pszUrl = ppath ? ppath : "/"; if (usingProxy && phost && !nlc->dnsThroughProxy) { char* tszHost = mir_strdup(phost); if (ppath && phost) tszHost[ppath - phost] = 0; char* cln = strchr(tszHost, ':'); if (cln) *cln = 0; if (inet_addr(tszHost) == INADDR_NONE) { DWORD ip = DnsLookup(nlu, tszHost); if (ip && szHost) { mir_free(szHost); szHost = (char*)mir_alloc(64); if (cln) *cln = ':'; mir_snprintf(szHost, 64, "%s%s", inet_ntoa(*(PIN_ADDR)&ip), cln ? cln : ""); } } mir_free(tszHost); } } } if (nlc->proxyAuthNeeded && proxyAuthList.getCount()) { if (httpSecurity.m_szProvider == NULL && nlc->szProxyServer) { const char *szAuthMethodNlu = proxyAuthList.find(nlc->szProxyServer); if (szAuthMethodNlu) { mir_free(pszProxyAuthHdr); pszProxyAuthHdr = httpSecurity.Execute(nlc, nlc->szProxyServer, szAuthMethodNlu, "", complete); } } } nlc->proxyAuthNeeded = false; AppendToCharBuffer(&httpRequest, "%s %s HTTP/1.%d\r\n", pszRequest, pszUrl, (nlhr->flags & NLHRF_HTTP11) != 0); //HTTP headers doneHostHeader = doneContentLengthHeader = doneProxyAuthHeader = doneAuthHeader = 0; for (i=0; i < nlhr->headersCount; i++) { NETLIBHTTPHEADER &p = nlhr->headers[i]; if (!mir_strcmpi(p.szName, "Host")) doneHostHeader = 1; else if (!mir_strcmpi(p.szName, "Content-Length")) doneContentLengthHeader = 1; else if (!mir_strcmpi(p.szName, "Proxy-Authorization")) doneProxyAuthHeader = 1; else if (!mir_strcmpi(p.szName, "Authorization")) doneAuthHeader = 1; else if (!mir_strcmpi(p.szName, "Connection")) continue; if (p.szValue == NULL) continue; AppendToCharBuffer(&httpRequest, "%s: %s\r\n", p.szName, p.szValue); } if (szHost && !doneHostHeader) AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Host", szHost); if (pszProxyAuthHdr && !doneProxyAuthHeader) AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Proxy-Authorization", pszProxyAuthHdr); if (pszAuthHdr && !doneAuthHeader) AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Authorization", pszAuthHdr); AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Connection", "Keep-Alive"); AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Proxy-Connection", "Keep-Alive"); // Add Sticky Headers if (nlu->szStickyHeaders != NULL) AppendToCharBuffer(&httpRequest, "%s\r\n", nlu->szStickyHeaders); //send it bytesSent = SendHttpRequestAndData(nlc, &httpRequest, nlhr, !doneContentLengthHeader); if (bytesSent == SOCKET_ERROR) break; //ntlm reply if (doneContentLengthHeader && nlhr->requestType != REQUEST_HEAD) break; DWORD fflags = MSG_PEEK | MSG_NODUMP | ((nlhr->flags & NLHRF_NOPROXY) ? MSG_RAW : 0); DWORD dwTimeOutTime = hdrTimeout < 0 ? -1 : GetTickCount() + hdrTimeout; if (!HttpPeekFirstResponseLine(nlc, dwTimeOutTime, fflags, &nlhr->resultCode, NULL, NULL)) { DWORD err = GetLastError(); NetlibLogf(nlu, "%s %d: %s Failed (%u %u)", __FILE__, __LINE__, "HttpPeekFirstResponseLine", err, count); // connection died while we were waiting if (GetNetlibHandleType(nlc) != NLH_CONNECTION) { nlc = NULL; break; } if (err == ERROR_TIMEOUT || err == ERROR_BAD_FORMAT || err == ERROR_BUFFER_OVERFLOW || lastFirstLineFail || nlc->termRequested || nlhr->requestType == REQUEST_CONNECT) { bytesSent = SOCKET_ERROR; break; } lastFirstLineFail = true; continue; } int resultCode = nlhr->resultCode; lastFirstLineFail = false; DWORD hflags = (nlhr->flags & (NLHRF_NODUMP | NLHRF_NODUMPHEADERS | NLHRF_NODUMPSEND) ? MSG_NODUMP : (nlhr->flags & NLHRF_DUMPPROXY ? MSG_DUMPPROXY : 0)) | (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0); DWORD dflags = (nlhr->flags & (NLHRF_NODUMP | NLHRF_NODUMPSEND) ? MSG_NODUMP : MSG_DUMPASTEXT | MSG_DUMPPROXY) | (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0) | MSG_NODUMP; if (resultCode == 100) nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags); else if (resultCode == 307 || ((resultCode == 301 || resultCode == 302) && (nlhr->flags & NLHRF_REDIRECT))) { // redirect pszUrl = NULL; if (nlhr->requestType == REQUEST_HEAD) nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags); else nlhrReply = NetlibHttpRecv(nlc, hflags, dflags); if (nlhrReply) { char* tmpUrl = NetlibHttpFindHeader(nlhrReply, "Location"); if (tmpUrl) { size_t rlen = 0; if (tmpUrl[0] == '/') { const char *ppath, *phost; phost = strstr(pszFullUrl, "://"); phost = phost ? phost + 3 : pszFullUrl; ppath = strchr(phost, '/'); rlen = ppath ? ppath - pszFullUrl : mir_strlen(pszFullUrl); } nlc->szNewUrl = (char*)mir_realloc(nlc->szNewUrl, rlen + mir_strlen(tmpUrl) * 3 + 1); strncpy(nlc->szNewUrl, pszFullUrl, rlen); mir_strcpy(nlc->szNewUrl + rlen, tmpUrl); pszFullUrl = nlc->szNewUrl; pszUrl = NULL; if (NetlibHttpProcessUrl(nlhr, nlu, nlc, pszFullUrl) == NULL) { bytesSent = SOCKET_ERROR; break; } } else { NetlibHttpSetLastErrorUsingHttpResult(resultCode); bytesSent = SOCKET_ERROR; break; } } else { NetlibHttpSetLastErrorUsingHttpResult(resultCode); bytesSent = SOCKET_ERROR; break; } } else if (resultCode == 401 && !doneAuthHeader) { //auth required if (nlhr->requestType == REQUEST_HEAD) nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags); else nlhrReply = NetlibHttpRecv(nlc, hflags, dflags); mir_free(pszAuthHdr); pszAuthHdr = NULL; if (nlhrReply) { char *szAuthStr = NULL; if (!complete) { szAuthStr = NetlibHttpFindAuthHeader(nlhrReply, "WWW-Authenticate", httpSecurity.m_szProvider); if (szAuthStr) { char *szChallenge = strchr(szAuthStr, ' '); if (!szChallenge || !*lrtrimp(szChallenge)) complete = true; } } if (complete && httpSecurity.m_hNtlmSecurity) szAuthStr = httpSecurity.TryBasic() ? NetlibHttpFindAuthHeader(nlhrReply, "WWW-Authenticate", "Basic") : NULL; if (szAuthStr) { char *szChallenge = strchr(szAuthStr, ' '); if (szChallenge) { *szChallenge = 0; szChallenge = lrtrimp(szChallenge + 1); } pszAuthHdr = httpSecurity.Execute(nlc, szHost, szAuthStr, szChallenge, complete); } } if (pszAuthHdr == NULL) { proxyAuthList.add(szHost, NULL); NetlibHttpSetLastErrorUsingHttpResult(resultCode); bytesSent = SOCKET_ERROR; break; } } else if (resultCode == 407 && !doneProxyAuthHeader) { //proxy auth required if (nlhr->requestType == REQUEST_HEAD) nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags); else nlhrReply = NetlibHttpRecv(nlc, hflags, dflags); mir_free(pszProxyAuthHdr); pszProxyAuthHdr = NULL; if (nlhrReply) { char *szAuthStr = NULL; if (!complete) { szAuthStr = NetlibHttpFindAuthHeader(nlhrReply, "Proxy-Authenticate", httpSecurity.m_szProvider); if (szAuthStr) { char *szChallenge = strchr(szAuthStr, ' '); if (!szChallenge || !*lrtrimp(szChallenge + 1)) complete = true; } } if (complete && httpSecurity.m_hNtlmSecurity) szAuthStr = httpSecurity.TryBasic() ? NetlibHttpFindAuthHeader(nlhrReply, "Proxy-Authenticate", "Basic") : NULL; if (szAuthStr) { char *szChallenge = strchr(szAuthStr, ' '); if (szChallenge) { *szChallenge = 0; szChallenge = lrtrimp(szChallenge + 1); } pszProxyAuthHdr = httpSecurity.Execute(nlc, nlc->szProxyServer, szAuthStr, szChallenge, complete); } } if (pszProxyAuthHdr == NULL) { proxyAuthList.add(nlc->szProxyServer, NULL); NetlibHttpSetLastErrorUsingHttpResult(resultCode); bytesSent = SOCKET_ERROR; break; } } else break; if (pszProxyAuthHdr && resultCode != 407 && !doneProxyAuthHeader) replaceStr(pszProxyAuthHdr, NULL); if (pszAuthHdr && resultCode != 401 && !doneAuthHeader) replaceStr(pszAuthHdr, NULL); if (nlhrReply) { NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply); nlhrReply = NULL; } } if (count == 0) bytesSent = SOCKET_ERROR; if (nlhrReply) NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply); //clean up mir_free(pszProxyAuthHdr); mir_free(pszAuthHdr); mir_free(szHost); mir_free(szNewUrl); if (nlc && !nlc->usingHttpGateway) NetlibLeaveNestedCS(&nlc->ncsSend); return bytesSent; }