bool KviHttpRequest::processHeader(KviCString &szHeader) { int idx = szHeader.findFirstIdx("\r\n"); KviCString szResponse; if(idx != -1) { szResponse = szHeader.left(idx); szHeader.cutLeft(idx + 2); } else { szResponse = szHeader; szHeader = ""; } szResponse.trim(); bool bValid = false; unsigned int uStatus = 0; // check the response value if(kvi_strEqualCSN(szResponse.ptr(),"HTTP",4)) { KviCString szR = szResponse; szR.cutToFirst(' '); szR.trim(); int idx = szR.findFirstIdx(' '); KviCString szNumber; if(idx != -1)szNumber = szR.left(idx); else szNumber = szR; bool bOk; uStatus = szNumber.toUInt(&bOk); if(bOk)bValid = true; } QString szUniResponse = QString::fromUtf8(szResponse.ptr()); if(!bValid) { // the response is invalid ? resetInternalStatus(); m_szLastError = __tr2qs("Invalid HTTP response: %1").arg(szUniResponse); emit terminated(false); return false; } emit status(__tr2qs("Received HTTP response: %1").arg(szUniResponse)); KviPointerList<KviCString> hlist; hlist.setAutoDelete(true); idx = szHeader.findFirstIdx("\r\n"); while(idx != -1) { if(idx > 0) { hlist.append(new KviCString(szHeader.ptr(),idx)); szHeader.cutLeft(idx + 2); } idx = szHeader.findFirstIdx("\r\n"); } if(szHeader.hasData())hlist.append(new KviCString(szHeader)); KviPointerHashTable<const char *,KviCString> hdr(11,false,true); hdr.setAutoDelete(true); for(KviCString * s = hlist.first();s;s = hlist.next()) { idx = s->findFirstIdx(":"); if(idx != -1) { KviCString szName = s->left(idx); s->cutLeft(idx + 1); s->trim(); hdr.replace(szName.ptr(),new KviCString(*s)); //qDebug("FOUND HEADER (%s)=(%s)",szName.ptr(),s->ptr()); } } KviCString * size = hdr.find("Content-length"); if(size) { bool bOk; m_uTotalSize = size->toUInt(&bOk); if(!bOk)m_uTotalSize = 0; } KviCString * contentEncoding = hdr.find("Content-encoding"); if(contentEncoding) { m_bGzip = contentEncoding->equalsCI("gzip"); } KviCString * transferEncoding = hdr.find("Transfer-Encoding"); if(transferEncoding) { if(kvi_strEqualCI(transferEncoding->ptr(),"chunked")) { // be prepared to handle the chunked transfer encoding as required by HTTP/1.1 m_bChunkedTransferEncoding = true; m_uRemainingChunkSize = 0; } } // check the status // case 200: // OK // case 206: // Partial content // case 100: // Continue ?? // case 101: // Switching protocols ??? // case 201: // Created // case 202: // Accepted // case 203: // Non-Authoritative Information // case 204: // No content // case 205: // Reset content // case 300: // Multiple choices // case 301: // Moved permanently // case 302: // Found // case 303: // See Other // case 304: // Not modified // case 305: // Use Proxy // case 306: // ??? // case 307: // Temporary Redirect // case 400: // Bad request // case 401: // Unauthorized // case 402: // Payment Required // case 403: // Forbidden // case 404: // Not found // case 405: // Method not allowed // case 406: // Not acceptable // case 407: // Proxy authentication required // case 408: // Request timeout // case 409: // Conflict // case 410: // Gone // case 411: // Length required // case 412: // Precondition failed // case 413: // Request entity too large // case 414: // Request-URI Too Long // case 415: // Unsupported media type // case 416: // Requested range not satisfiable // case 417: // Expectation Failed // case 500: // Internal server error // case 501: // Not implemented // case 502: // Bad gateway // case 503: // Service unavailable // case 504: // Gateway timeout // case 505: // HTTP Version not supported if( (uStatus != 200) && // OK (uStatus != 206) // Partial content ) { // This is not "OK" and not "Partial content" // Error, redirect or something confusing if(m_eProcessingType != HeadersOnly) { switch(uStatus) { case 301: // Moved permanently case 302: // Found case 303: // See Other case 307: // Temporary Redirect { if(!m_bFollowRedirects) { resetInternalStatus(); m_szLastError = szResponse.ptr(); emit terminated(false); return false; } m_uRedirectCount++; if(m_uRedirectCount > m_uMaximumRedirectCount) { resetInternalStatus(); m_szLastError = __tr2qs("Too many redirects"); emit terminated(false); return false; } KviCString * location = hdr.find("Location"); if(!location) { resetInternalStatus(); m_szLastError = __tr2qs("Bad redirect"); emit terminated(false); return false; } KviUrl url(location->ptr()); if( (url.url() == m_connectionUrl.url()) || (url.url() == m_url.url()) ) { resetInternalStatus(); m_szLastError = __tr2qs("Redirect loop"); emit terminated(false); return false; } m_connectionUrl = url; emit status(__tr2qs("Following Redirect to %1").arg(url.url())); if(!start()) emit terminated(false); return false; // will exit the call stack } break; break; default: // assume error resetInternalStatus(); m_szLastError = szResponse.ptr(); emit terminated(false); return false; break; } // this is an error then } // else the server will terminate (it was a HEAD request) } emit receivedResponse(szUniResponse); emit header(&hdr); if((m_uMaxContentLength > 0) && (m_uTotalSize > ((unsigned int)m_uMaxContentLength))) { resetInternalStatus(); m_szLastError=__tr2qs("The amount of received data exceeds the maximum length"); emit terminated(false); return false; } // fixme: could check for data type etc... return true; }
bool KviIsOnNotifyListManager::handleUserhost(KviIrcMessage * msg) { if(!m_bExpectingUserhost) return false; // first check for consistency: all the replies must be on the USERHOST list KviPointerList<KviIrcMask> tmplist; tmplist.setAutoDelete(true); KviCString nk; const char * aux = msg->trailing(); while(*aux) { nk = ""; aux = kvi_extractToken(nk, aux, ' '); if(nk.hasData()) { // split it in a mask KviCString nick; KviCString user; KviCString host; int idx = nk.findFirstIdx('='); if(idx != -1) { nick = nk.left(idx); if(nick.lastCharIs('*')) nick.cutRight(1); nk.cutLeft(idx + 1); if(nk.firstCharIs('+') || nk.firstCharIs('-')) nk.cutLeft(1); idx = nk.findFirstIdx('@'); if(idx != -1) { user = nk.left(idx); nk.cutLeft(idx + 1); host = nk; } else { user = "******"; host = nk; } bool bGotIt = false; QString szNick = m_pConnection->decodeText(nick.ptr()); QString szUser = m_pConnection->decodeText(user.ptr()); QString szHost = m_pConnection->decodeText(host.ptr()); for(QString * s = m_pUserhostList->first(); s && (!bGotIt); s = m_pUserhostList->next()) { if(KviQString::equalCI(*s, szNick)) { KviIrcMask * mk = new KviIrcMask(szNick, szUser, szHost); tmplist.append(mk); bGotIt = true; m_pUserhostList->removeRef(s); } } if(!bGotIt) { // ops...not my userhost! if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMWARNING, __tr2qs("Notify list: Hey! You've used USERHOST behind my back? (I might be confused now...)")); return false; } } else { if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMWARNING, __tr2qs("Notify list: Broken USERHOST reply from the server? (%s)"), nk.ptr()); } } } // Ok...looks to be my usershot (still not sure at 100%, but can't do better) if(m_pConnection->lagMeter()) m_pConnection->lagMeter()->lagCheckComplete("@notify_userhost"); m_bExpectingUserhost = false; for(KviIrcMask * mk = tmplist.first(); mk; mk = tmplist.next()) { if(!doMatchUser(mk->nick(), *mk)) return true; // have to restart!!! } if(!(m_pUserhostList->isEmpty())) { // ops...someone is no longer online ? while(QString * s = m_pUserhostList->first()) { if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMMESSAGE, __tr2qs("Notify list: \r!n\r%Q\r appears to have gone offline before USERHOST reply was received, will recheck in the next loop"), s); m_pUserhostList->removeFirst(); } } if(m_pOnlineList->isEmpty()) { if(m_pNotifyList->isEmpty()) delayedNotifySession(); else delayedIsOnSession(); } else delayedUserhostSession(); return true; }
bool KviIsOnNotifyListManager::handleUserhost(KviIrcMessage * msg) { if(!m_bExpectingUserhost) return false; // first check for consistency: all the replies must be on the USERHOST list std::map<std::size_t, std::unique_ptr<KviIrcMask>> tmplist; KviCString nk; const char * aux = msg->trailing(); while(*aux) { nk = ""; aux = kvi_extractToken(nk, aux, ' '); if(nk.hasData()) { // split it in a mask KviCString nick; KviCString user; KviCString host; int idx = nk.findFirstIdx('='); if(idx != -1) { nick = nk.left(idx); if(nick.lastCharIs('*')) nick.cutRight(1); nk.cutLeft(idx + 1); if(nk.firstCharIs('+') || nk.firstCharIs('-')) nk.cutLeft(1); idx = nk.findFirstIdx('@'); if(idx != -1) { user = nk.left(idx); nk.cutLeft(idx + 1); host = nk; } else { user = "******"; host = nk; } bool bGotIt = false; QString szNick = m_pConnection->decodeText(nick.ptr()); QString szUser = m_pConnection->decodeText(user.ptr()); QString szHost = m_pConnection->decodeText(host.ptr()); std::size_t i = 0; for(const auto & s : m_UserhostList) { if(KviQString::equalCI(s, szNick)) { tmplist.emplace(i, std::make_unique<KviIrcMask>(szNick, szUser, szHost)); bGotIt = true; break; } } if(!bGotIt) { // oops... not my userhost! if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMWARNING, __tr2qs("Notify list: Hey! You've used USERHOST behind my back? (I might be confused now...)")); return false; } } else { if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMWARNING, __tr2qs("Notify list: Broken USERHOST reply from the server? (%s)"), nk.ptr()); } } } // Ok... looks to be my usershot (still not sure at 100%, but can't do better) if(m_pConnection->lagMeter()) m_pConnection->lagMeter()->lagCheckComplete("@notify_userhost"); m_bExpectingUserhost = false; for(auto & pair : tmplist) { KviIrcMask * mk = pair.second.get(); if(!doMatchUser(mk->nick(), *mk)) return true; // have to restart!!! } for(auto i = tmplist.rbegin(); i != tmplist.rend(); ++i) m_UserhostList.erase(m_UserhostList.begin() + i->first); for(const auto & s : m_UserhostList) { // oops... someone is no longer online ? if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMMESSAGE, __tr2qs("Notify list: \r!n\r%Q\r appears to have gone offline before USERHOST reply was received, will recheck in the next loop"), &s); } m_UserhostList.clear(); if(m_OnlineList.empty()) { if(m_NotifyList.empty()) delayedNotifySession(); else delayedIsOnSession(); } else { delayedUserhostSession(); } return true; }