📄 http.cc
字号:
if (!m_lastModified.isEmpty()) header += "If-Modified-Since: "+m_lastModified+"\r\n"; } header += "Accept: "; QString acceptHeader = config()->readEntry("accept"); if (!acceptHeader.isEmpty()) header += acceptHeader; else header += DEFAULT_ACCEPT_HEADER; header += "\r\n"; if ( config()->readBoolEntry("AllowCompressedPage", true) ) {#ifdef DO_GZIP // Content negotiation // header += "Accept-Encoding: x-gzip, x-deflate, gzip, deflate, identity\r\n"; header += "Accept-Encoding: x-gzip, gzip, identity\r\n";#endif } if ( config()->readBoolEntry("SendLanguageSettings", true) ) { m_strCharsets = config()->readEntry( "Charsets", DEFAULT_FULL_CHARSET_HEADER ); if ( !m_strCharsets.isEmpty() ) m_strCharsets += DEFAULT_PARIAL_CHARSET_HEADER; header += "Accept-Charset: " + m_strCharsets + "\r\n"; m_strLanguages = config()->readEntry( "Languages", DEFAULT_LANGUAGE_HEADER ); header += "Accept-Language: " + m_strLanguages + "\r\n"; } /* support for virtual hosts and required by HTTP 1.1 */ header += "Host: "; if (m_state.hostname.find(':') != -1) { // This is an IPv6 (not hostname) header += '['; header += m_state.hostname; header += ']'; } else { header += m_state.hostname; } if (m_state.port != m_iDefaultPort) header += QString(":%1").arg(m_state.port); header += "\r\n"; QString cookieStr; QString cookieMode = config()->readEntry("cookies").lower(); if (cookieMode == "none") { m_cookieMode = CookiesNone; } else if (cookieMode == "manual") { m_cookieMode = CookiesManual; cookieStr = config()->readEntry("setcookies"); } else { m_cookieMode = CookiesAuto; if (m_bUseCookiejar) cookieStr = findCookies( m_request.url.url()); } if (!cookieStr.isEmpty()) header += cookieStr + "\r\n"; if (m_request.method == HTTP_POST) { header += config()->readEntry("content-type"); header += "\r\n"; } // Only check for a cached copy if the previous // response was NOT a 401 or 407. if ( m_responseCode != 401 && m_responseCode != 407 ) { AuthInfo info; info.url = m_request.url; info.verifyPath = true; if ( !m_request.user.isEmpty() ) info.username = m_request.user; if ( checkCachedAuthentication( info ) ) { Authentication = info.digestInfo.isEmpty() ? AUTH_Basic : AUTH_Digest ; m_state.user = info.username; m_state.passwd = info.password; m_strRealm = info.realmValue; if ( Authentication == AUTH_Digest ) m_strAuthorization = info.digestInfo; } } switch ( Authentication ) { case AUTH_Basic: header += createBasicAuth(); header+="\r\n"; break; case AUTH_Digest: header += createDigestAuth(); header+="\r\n"; break; case AUTH_None: default: break; } /********* Only for debugging purpose *********/ if ( Authentication != AUTH_None ) { kdDebug(7113) << "(" << getpid() << ") Using Authentication: " << endl; kdDebug(7113) << "(" << getpid() << ") Host= " << m_state.hostname << endl; kdDebug(7113) << "(" << getpid() << ") Port= " << m_state.port << endl; kdDebug(7113) << "(" << getpid() << ") User= " << m_state.user << endl; kdDebug(7113) << "(" << getpid() << ") Password= [protected]" << endl; kdDebug(7113) << "(" << getpid() << ") Realm= " << m_strRealm << endl; kdDebug(7113) << "(" << getpid() << ") Extra= " << m_strAuthorization << endl; } // Do we need to authorize to the proxy server ? if ( m_state.doProxy && !m_bIsTunneled ) header += proxyAuthenticationHeader(); } kdDebug(7103) << "======= Begin header =======" << endl; QStringList headerOutput = QStringList::split( '\n', header ); QStringList::Iterator it = headerOutput.begin(); for ( ; it != headerOutput.end(); ++it ) kdDebug(7103) << "(" << getpid() << ") " << (*it) << endl; if ( !moreData ) header += "\r\n"; /* end header */ // Now that we have our formatted header, let's send it! bool sendOk; sendOk = (write(header.latin1(), header.length()) == (ssize_t) header.length()); if (!sendOk) { kdDebug(7113) << "(" << getpid() << ") Connection broken! (" << m_state.hostname << ")" << endl; if (m_bKeepAlive) { // With a Keep-Alive connection this can happen. // Just reestablish the connection. http_closeConnection(); if (!http_openConnection()) return false; sendOk = (write(header.latin1(), header.length()) == (ssize_t) header.length()); } if (!sendOk) { kdDebug(7113) << "(" << getpid() << ") sendOk==false. Connnection broken ! " << endl; error( ERR_CONNECTION_BROKEN, m_state.hostname ); return false; } } bool res = moreData ? sendBody() : true; infoMessage( i18n( "<b>%1</b> contacted. Waiting for reply..." ).arg( m_request.hostname ) ); return res;}/** * This function will read in the return header from the server. It will * not read in the body of the return message. It will also not transmit * the header to our client as the client doesn't need to know the gory * details of HTTP headers. */bool HTTPProtocol::readHeader(){ // Check if (m_bCachedRead) { // Read header from cache... char buffer[4097]; if (!fgets(buffer, 4096, m_fcache) ) { // Error, delete cache entry kdDebug(7113) << "(" << getpid() << ") readHeader: Connnection broken ! " << endl; error( ERR_CONNECTION_BROKEN, m_state.hostname ); return false; } kdDebug(7113) << "(" << getpid() << ") readHeader: returning mimetype " << buffer << endl; m_strMimeType = QString::fromUtf8( buffer).stripWhiteSpace(); mimeType(m_strMimeType); if (!fgets(buffer, 4096, m_fcache) ) { // Error, delete cache entry kdDebug(7113) << "(" << getpid() << ") readHeader(2): Connnection broken ! " << endl; error( ERR_CONNECTION_BROKEN, m_state.hostname ); return false; } m_strCharset = QString::fromUtf8( buffer).stripWhiteSpace().lower(); setMetaData("charset", m_strCharset); return true; } m_etag = QString::null; m_lastModified = QString::null; m_strCharset = QString::null; time_t dateHeader = 0; time_t expireDate = 0; // 0 = no info, 1 = already expired, > 1 = actual date int currentAge = 0; int maxAge = -1; // -1 = no max age, 0 already expired, > 0 = actual time QCString locationStr; // In case we get a redirect. QCString cookieStr; // In case we get a cookie. QString disposition; // Incase we get a Content-Disposition QString errMessage; // for handling errorPages... // read in 4096 bytes at a time (HTTP cookies can be quite large.) int len = 0; char buffer[4097]; bool cont = false; bool cacheValidated = false; // Revalidation was successfull bool mayCache = true; bool hasCacheDirective = false; int errCode = -1; // incase we error out... if (!waitForResponse(m_remoteRespTimeout)) { // No response error error( ERR_SERVER_TIMEOUT , m_state.hostname ); return false; } gets(buffer, sizeof(buffer)-1); if (m_bEOF) { kdDebug(7113) << "(" << getpid() << ") readHeader: EOF while waiting for header start." << endl; if (m_bKeepAlive) // Try to reestablish connection. { http_closeConnection(); if ( !http_open() ) return false; if (!waitForResponse(m_remoteRespTimeout)) { // No response error error( ERR_SERVER_TIMEOUT, m_state.hostname ); return false; } gets(buffer, sizeof(buffer)-1); } if (m_bEOF) { if (m_request.method == HTTP_HEAD) { // HACK // Some web-servers fail to respond properly to a HEAD request. // We compensate for their failure to properly implement the HTTP standard // by assuming that they will be sending html. mimeType(QString::fromLatin1(DEFAULT_MIME_TYPE)); return true; } kdDebug(7113) << "(" << getpid() << ") readHeader(3): Connnection broken ! " << endl; error( ERR_CONNECTION_BROKEN, m_state.hostname ); return false; } } kdDebug(7103) << "======= Begin Response =======" << endl; do { // strip off \r and \n if we have them len = strlen(buffer); while(len && (buffer[len-1] == '\n' || buffer[len-1] == '\r')) buffer[--len] = 0; // if there was only a newline then continue if (!len) { kdDebug(7103) << "(" << getpid() << ") --empty--" << endl; continue; } kdDebug(7103) << "(" << getpid() << ") " << buffer <<endl; // Save broken servers from damnation!! char* buf = buffer; while( *buf == ' ' ) buf++; // We got a header back ! if (strncasecmp(buf, "HTTP/", 5) == 0) { if (strncmp(buf+5, "1.0 ",4) == 0) { m_HTTPrev = HTTP_10; m_bKeepAlive = false; } else // Assume everything else to be 1.1 or higher.... { m_HTTPrev = HTTP_11; // Connections with proxies are closed by default because // some proxies like junkbuster can't handle persistent // connections but don't tell us. // We will still use persistent connections if the proxy // sends us a "Connection: Keep-Alive" header. if (m_state.doProxy) { m_bKeepAlive = false; } else { if (!m_bIsSSL) m_bKeepAlive = true; // HTTP 1.1 has persistant connections. } } if ( m_responseCode ) m_prevResponseCode = m_responseCode; m_responseCode = atoi(buf+9); setMetaData( "http-responseCode", QString::number(m_responseCode) ); // server side errors if (m_responseCode >= 500 && m_responseCode <= 599) { if (m_request.method == HTTP_HEAD) { /*Ignore error*/ } else { if (m_bErrorPage) errCode = 0; else { errCode = ERR_COULD_NOT_CONNECT; errMessage = m_request.url.url(); } } m_bCachedWrite = false; // Don't put in cache mayCache = false; } // Unauthorized access else if (m_responseCode == 401 || m_responseCode == 407) { // Double authorization requests, i.e. a proxy auth // request followed immediately by a regular auth request. if ( m_prevResponseCode != m_responseCode && (m_prevResponseCode == 401 || m_prevResponseCode == 407) ) saveAuthorization(); m_bUnauthorized = true; m_bCachedWrite = false; // Don't put in cache mayCache = false; } // Any other client errors else if (m_responseCode >= 400 && m_responseCode <= 499) { // Tell that we will only get an error page here. if (m_bErrorPage) errCode = 0; else { errCode = ERR_COULD_NOT_CONNECT; errMessage = m_request.url.url(); } m_bCachedWrite = false; // Don't put in cache mayCache = false; } else if (m_responseCode == 307) { // 307 Temporary Redirect m_bCachedWrite = false; // Don't put in cache mayCache = false; } else if (m_responseCode == 304) { // 304 Not Modified // The value in our cache is still valid. cacheValidated = true; } else if (m_responseCode >= 301 && m_responseCode<= 303) { // 301 Moved permanently // 302 Found (temporary location) // 303 See Other if (m_request.method != HTTP_HEAD && m_request.method != HTTP_GET) { // NOTE: This is wrong according to RFC 2616. However, // because most other existing user agent implementations // treat a 301/302 response as a 303 response and preform // a GET action regardless of what the previous method was, // many servers have simply adapted to this way of doing // things!! Thus, we are forced to do the same thing or we // won't be able to retrieve these pages correctly!! This // implementation is therefore only correct for a 303 response // according to RFC 2616 section 10.3.2/3/4/8 m_request.method = HTTP_GET; // Force a GET } m_bCachedWrite = false; // Don't put in cache mayCache = false; } else if ( m_responseCode == 204 ) // No content { // error(ERR_NO_CONTENT, i18n("Data have been successfully sent.")); // Short circuit and do nothing! m_bError = true; return false; } else if ( m_responseCode == 206 ) { if ( m_request.offset ) m_bCanResume = true; } else if (m_responseCode == 100) { // We got 'Continue' - ignore it cont = true; } } // are we allowd to resume? this will tell us else if (strncasecmp(buf, "Accept-Ranges:", 14) == 0) { if (strncasecmp(trimLead(buf + 14), "none", 4) == 0) m_bCanResume = false; } // Cache control else if (strncasecmp(buf, "Cache-Control:", 14) == 0) { QStringList cacheControls = QStringList::split(',', QString::fromLatin1(trimLead(buf+14))); for(QStringList::ConstIterator it = cacheControls.begin(); it != cacheControls.end(); it++) { QString cacheControl = (*it).stripWhiteSpace(); if (strncasecmp(cacheControl.latin1(), "no-cache", 8) == 0) { m_bCachedWrite = false; // Don't put in cache mayCache = false; } else if (strncasecmp(cacheControl.latin1(), "no-store", 8) == 0) { m_bCachedWrite = false; // Don't put in cache mayCache = false; } else if (strncasecmp(cacheControl.latin1(), "max-age=", 8) == 0) { maxAge = atol(cacheControl.mid(8).stripWhiteSpace().latin1()); } } hasCacheDirective = true; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -