📄 http.cc
字号:
nbytes -= n; buf += n; bytes_sent += n; } return bytes_sent;}char *HTTPProtocol::gets (char *s, int size){ int len=0; char *buf=s; char mybuf[2]={0,0}; while (len < size) { read(mybuf, 1); if (*mybuf == '\r') // Ignore! continue; if (*mybuf == '\n') break; *buf++ = *mybuf; len++; } *buf=0; return s;}void HTTPProtocol::ungets(char *str, int size){ char *newbuf = (char *) malloc(size+1+m_lineCountUnget); memcpy(newbuf, str, size ); newbuf[size] = '\n'; if (m_lineCountUnget) memcpy(newbuf+size+1, m_linePtrUnget, m_lineCountUnget); if (m_lineBufUnget) free(m_lineBufUnget); m_lineBufUnget = newbuf; m_linePtrUnget = newbuf; m_lineCountUnget = size+1+m_lineCountUnget;}ssize_t HTTPProtocol::read (void *b, size_t nbytes){ ssize_t ret = 0; if (m_lineCountUnget > 0) { ret = ( nbytes < m_lineCountUnget ? nbytes : m_lineCountUnget ); m_lineCountUnget -= ret; memcpy(b, m_linePtrUnget, ret); m_linePtrUnget += ret; if (m_lineCountUnget == 0) { free(m_lineBufUnget); m_lineBufUnget = 0; } return ret; } if (m_lineCount > 0) { ret = ( nbytes < m_lineCount ? nbytes : m_lineCount ); m_lineCount -= ret; memcpy(b, m_linePtr, ret); m_linePtr += ret; return ret; } if (nbytes == 1) { m_lineCount = read(m_lineBuf, 1024); // Read into buffer m_linePtr = m_lineBuf; if (m_lineCount <= 0) return ret; return read(b, 1); // Read from buffer } do { ret = Read( b, nbytes); if (ret == 0) m_bEOF = true; } while (( ret == -1) && ((errno == EAGAIN) || (errno == EINTR))); return ret;}void HTTPProtocol::http_checkConnection(){ if ( m_iSock != -1 ) { bool closeDown = false; if ( m_request.doProxy && m_state.doProxy ) { // Keep the connection to the proxy. } else if ( !m_state.doProxy && !m_request.doProxy ) { if (m_state.hostname != m_request.hostname) { closeDown = true; } else if (m_state.port != m_request.port) { closeDown = true; } else if (m_state.user != m_request.user) { closeDown = true; } else if (m_state.passwd != m_request.passwd) { closeDown = true; } } else { closeDown = true; } if (!closeDown && !isConnectionValid()) closeDown = true; if (closeDown) http_closeConnection(); } // Let's update our current state m_state.hostname = m_request.hostname; m_state.port = m_request.port; m_state.user = m_request.user; m_state.passwd = m_request.passwd; m_state.doProxy = m_request.doProxy;}bool HTTPProtocol::http_openConnection(){ m_bKeepAlive = false; setBlockConnection( true ); int errCode; QString errMsg; if ( m_state.doProxy ) { QString proxy_host = m_proxyURL.host(); int proxy_port = m_proxyURL.port(); kdDebug(7113) << "(" << getpid() << ") http_openConnection " << proxy_host << " " << proxy_port << endl; infoMessage( i18n("Connecting to <b>%1</b>...").arg(m_state.hostname) ); setConnectTimeout( m_proxyConnTimeout ); if ( !ConnectToHost(proxy_host, proxy_port, false) ) { switch ( connectResult() ) { case IO_LookupError: errMsg = proxy_host; errCode = ERR_UNKNOWN_PROXY_HOST; break; case IO_TimeOutError: errMsg = i18n("Timed out while waiting to connect to %1").arg(proxy_host); errCode = ERR_SERVER_TIMEOUT; break; default: errMsg = i18n("Proxy %1 at port %2").arg(proxy_host).arg(proxy_port); errCode = ERR_COULD_NOT_CONNECT; } error( errCode, errMsg ); return false; } } else { // Apparently we don't want a proxy. let's just connect directly setConnectTimeout(m_remoteConnTimeout); if ( !ConnectToHost(m_state.hostname, m_state.port, false ) ) { switch ( connectResult() ) { case IO_LookupError: errMsg = m_state.hostname; errCode = ERR_UNKNOWN_HOST; break; case IO_TimeOutError: errMsg = i18n("Timed out while waiting to connect to %1").arg(m_state.hostname); errCode = ERR_SERVER_TIMEOUT; break; default: errCode = ERR_COULD_NOT_CONNECT; if (m_state.port != m_iDefaultPort) errMsg = i18n("%1 (port %2)").arg(m_state.hostname).arg(m_state.port); else errMsg = m_state.hostname; } error( errCode, errMsg ); return false; } } // Set our special socket option!! int on = 1; (void) setsockopt( m_iSock, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on) ); kdDebug(7113) << "(" << getpid() << ") Sending connected @ " << time(0L) << endl; connected(); return true;}/** * This function is responsible for opening up the connection to the remote * HTTP server and sending the header. If this requires special * authentication or other such fun stuff, then it will handle it. This * function will NOT receive anything from the server, however. This is in * contrast to previous incarnations of 'http_open'. * * The reason for the change is due to one small fact: some requests require * data to be sent in addition to the header (POST requests) and there is no * way for this function to get that data. This function is called in the * slotPut() or slotGet() functions which, in turn, are called (indirectly) as * a result of a KIOJob::put() or KIOJob::get(). It is those latter functions * which are responsible for starting up this ioslave in the first place. * This means that 'http_open' is called (essentially) as soon as the ioslave * is created -- BEFORE any data gets to this slave. * * The basic process now is this: * * 1) Open up the socket and port * 2) Format our request/header * 3) Send the header to the remote server */bool HTTPProtocol::http_open(){ // Cannot have an https request without the // m_bIsSSL being set! This can only happen // if InitializeSSL() call failed which in // turn means that SSL is not supported by // current installation !! if ( m_protocol == "https" && !m_bIsSSL ) { error( ERR_UNSUPPORTED_PROTOCOL, m_protocol ); return false; } http_checkConnection(); // Let's clear out some things, so bogus values aren't used. m_fcache = 0; m_lineCount = 0; m_lineCountUnget = 0; m_bCachedRead = false; m_bCachedWrite = false; m_bMustRevalidate = false; m_bEOF = false; m_iWWWAuthCount = 0; m_iProxyAuthCount = 0; m_sContentMD5 = QString::null; m_strMimeType = QString::null; m_qContentEncodings.clear(); m_qTransferEncodings.clear(); m_bChunked = false; m_bError = false; m_bErrorPage = config()->readBoolEntry("errorPage", true); m_iSize = -1; if (m_bUseCache) { m_fcache = checkCacheEntry( ); if (m_request.cache == CC_Reload && m_fcache) { if (m_fcache) fclose(m_fcache); m_fcache = 0; } m_bCachedWrite = true; if (m_fcache && !m_bMustRevalidate) { // Cache entry is OK. m_bCachedRead = true; // Cache hit. return true; } else if (!m_fcache) { m_bMustRevalidate = false; // Cache miss } else { // Conditional cache hit. (Validate) } if (m_request.cache == CC_CacheOnly) { error( ERR_DOES_NOT_EXIST, m_request.url.url() ); return false; } } // Let's try to open up our socket if we don't have one already. if ( m_iSock == -1) { if (!http_openConnection()) return false; } // Clean up previous POST bool moreData = false; // Variable to hold the entire header... QString header; // Determine if this is a POST or GET method switch ( m_request.method) { case HTTP_GET: header = "GET "; break; case HTTP_PUT: header = "PUT "; moreData = !isSSLTunnelEnabled(); m_bCachedWrite = false; // Do not put nay result in the cache break; case HTTP_POST: header = "POST "; moreData = !isSSLTunnelEnabled(); m_bCachedWrite = false; // Do not put nay result in the cache break; case HTTP_HEAD: header = "HEAD "; break; case HTTP_DELETE: header = "DELETE "; m_bCachedWrite = false; // Do not put nay result in the cache break; } if ( isSSLTunnelEnabled() ) { header = QString("CONNECT %1:%2 HTTP/1.1" "\r\n").arg( m_request.hostname).arg(m_request.port); // Identify who you are to the proxy server! if ( config()->readBoolEntry("SendUserAgent", true) ) { QString agent = config()->readEntry("UserAgent"); if( !agent.isEmpty() ) { header += "User-Agent: "; header += agent; header += "\r\n"; } } // Send the Host: information 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"; header += proxyAuthenticationHeader(); } else { // format the URI if (m_state.doProxy && !m_bIsTunneled) { KURL u; u.setUser( m_state.user ); u.setProtocol( m_protocol ); u.setHost( m_state.hostname ); if (m_state.port != m_iDefaultPort) u.setPort( m_state.port ); u.setEncodedPathAndQuery( m_request.url.encodedPathAndQuery(0,true) ); header += u.url(); } else { header += m_request.url.encodedPathAndQuery(0, true); } header += " HTTP/1.1\r\n"; /* start header */ // With SSL we don't keep the connection. if (m_bIsSSL) header += "Connection: Close\r\n"; else header += "Connection: Keep-Alive\r\n"; if ( config()->readBoolEntry("SendUserAgent", true) ) { QString agent = config()->readEntry("UserAgent"); if( !agent.isEmpty() ) header += "User-Agent: " + agent + "\r\n"; } bool sendReferrer = config()->readBoolEntry("SendReferrer", true); if ( sendReferrer ) { KURL referrerURL = config()->readEntry("referrer"); if (referrerURL.isValid()) { // Sanitize QString protocol = referrerURL.protocol(); if ((protocol == "http") || ((protocol == "https") && (m_protocol == "https")) ) { referrerURL.setRef(QString::null); referrerURL.setUser(QString::null); referrerURL.setPass(QString::null); header += "Referer: "; header += referrerURL.url(); header += "\r\n"; //Don't try to correct spelling! } } } // Adjust the offset value based on the "resume" meta-data. QString resumeOffset = config()->readEntry("resume"); if ( !resumeOffset.isEmpty() ) m_request.offset = resumeOffset.toInt(); if ( m_request.offset > 0 ) { header += QString("Range: bytes=%1-\r\n").arg(m_request.offset); kdDebug(7113) << "(" << getpid() << ") kio_http : Range = " << m_request.offset << endl; } if ( m_request.cache == CC_Reload ) { /* No caching for reload */ header += "Pragma: no-cache\r\n"; /* for HTTP/1.0 caches */ header += "Cache-control: no-cache\r\n"; /* for HTTP >=1.1 caches */ } if (m_bMustRevalidate) { /* conditional get */ if (!m_etag.isEmpty()) header += "If-None-Match: "+m_etag+"\r\n";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -