// send the request body to the client after having been handled by a DM plugin void DataBuffer::out(Socket *sock) throw(std::exception) { if (dontsendbody) { #ifdef DGDEBUG std::cout << "dontsendbody true; not sending" << std::endl; #endif return; } (*sock).readyForOutput(timeout); // exceptions on timeout or error if (tempfilefd > -1) { // must have been too big for ram so stream from disk in blocks #ifdef DGDEBUG std::cout << "Sending " << tempfilesize - bytesalreadysent << " bytes from temp file (" << bytesalreadysent << " already sent)" << std::endl; #endif off_t sent = bytesalreadysent; int rc; if (lseek(tempfilefd, bytesalreadysent, SEEK_SET) < 0) throw std::runtime_error(std::string("Can't write to socket: ") + strerror(errno)); while (sent < tempfilesize) { rc = readEINTR(tempfilefd, data, buffer_length); #ifdef DGDEBUG std::cout << "reading temp file rc:" << rc << std::endl; #endif if (rc < 0) { #ifdef DGDEBUG std::cout << "error reading temp file so throwing exception" << std::endl; #endif throw std::exception(); } if (rc == 0) { #ifdef DGDEBUG std::cout << "got zero bytes reading temp file" << std::endl; #endif break; // should never happen } // as it's cached to disk the buffer must be reasonably big if (!sock->writeToSocket(data, rc, 0, timeout)) { throw std::runtime_error(std::string("Can't write to socket: ") + strerror(errno)); } sent += rc; #ifdef DGDEBUG std::cout << "total sent from temp:" << sent << std::endl; #endif } close(tempfilefd); tempfilefd = -1; tempfilesize = 0; unlink(tempfilepath.toCharArray()); } else { #ifdef DGDEBUG std::cout << "Sending " << buffer_length - bytesalreadysent << " bytes from RAM (" << buffer_length << " in buffer; " << bytesalreadysent << " already sent)" << std::endl; #endif // it's in RAM, so just send it, no streaming from disk if (buffer_length != 0) { if (!sock->writeToSocket(data + bytesalreadysent, buffer_length - bytesalreadysent, 0, timeout)) throw std::exception(); } else { if (!sock->writeToSocket("\r\n\r\n", 4, 0, timeout)) throw std::exception(); } } }
// send file contents for scanning int icapinstance::scanFile(HTTPHeader * requestheader, HTTPHeader * docheader, const char *user, int filtergroup, const char *ip, const char *filename, NaughtyFilter * checkme, const String *disposition, const String *mimetype) { lastmessage = lastvirusname = ""; int filefd = open(filename, O_RDONLY); if (filefd < 0) { #ifdef DGDEBUG std::cerr << "Error opening file (" << filename << "): " << strerror(errno) << std::endl; #endif lastmessage = "Error opening file to send to ICAP"; syslog(LOG_ERR, "Error opening file to send to ICAP: %s", strerror(errno)); return DGCS_SCANERROR; } lseek(filefd, 0, SEEK_SET); unsigned int filesize = lseek(filefd, 0, SEEK_END); Socket icapsock; if (not doHeaders(icapsock, requestheader, docheader, filesize)) { icapsock.close(); close(filefd); return DGCS_SCANERROR; } lseek(filefd, 0, SEEK_SET); unsigned int sent = 0; char *data = new char[previewsize]; char *object = new char[100]; int objectsize = 0; #ifdef DGDEBUG std::cerr << "About to send file data to icap" << std::endl; if (usepreviews && (filesize > previewsize)) std::cerr << "Sending preview first" << std::endl; #endif if (usepreviews && (filesize > previewsize)) { try { while (sent < previewsize) { int rc = readEINTR(filefd, data, previewsize); if (rc < 0) { throw std::runtime_error("could not read from file"); } if (rc == 0) { break; // should never happen } if (!icapsock.writeToSocket(data, rc, 0, o.content_scanner_timeout)) { throw std::runtime_error("could not write to socket"); } memcpy(object, data, (rc > 100) ? 100 : rc); objectsize += (rc > 100) ? 100 : rc; sent += rc; } icapsock.writeString("\r\n0\r\n\r\n"); int rc = doScan(icapsock, docheader, object, objectsize, checkme); if (rc != ICAP_CONTINUE) { delete[] data; close(filefd); return rc; } // some servers send "continue" immediately followed by another response if (icapsock.checkForInput()) { int rc = doScan(icapsock, docheader, object, objectsize, checkme); if (rc != ICAP_NODATA) { delete[] data; close(filefd); return rc; } } char objectsizehex[32]; snprintf(objectsizehex, sizeof(objectsizehex), "%x\r\n", filesize-previewsize); icapsock.writeString(objectsizehex); } catch (std::exception& e) { #ifdef DGDEBUG std::cerr << "Exception sending message preview to ICAP: " << e.what() << std::endl; #endif icapsock.close(); lastmessage = "Exception sending message preview to ICAP"; syslog(LOG_ERR, "Exception sending message preview to ICAP: %s", e.what()); delete[] data; close(filefd); // this *might* just be an early response & closed connection if (icapsock.checkForInput()) { int rc = doScan(icapsock, docheader, object, objectsize, checkme); if (rc != ICAP_NODATA) return rc; } return DGCS_SCANERROR; } } delete[] data; data = new char[256 * 1024]; // 256k try { while (sent < filesize) { int rc = readEINTR(filefd, data, 256 * 1024); #ifdef DGDEBUG std::cout << "reading icap file rc: " << rc << std::endl; #endif if (rc < 0) { #ifdef DGDEBUG std::cout << "error reading icap file so throwing exception" << std::endl; #endif throw std::runtime_error("could not read from file"); } if (rc == 0) { #ifdef DGDEBUG std::cout << "got zero bytes reading icap file" << std::endl; #endif break; // should never happen } memcpy(object + objectsize, data, (rc > (100-objectsize)) ? (100-objectsize) : rc); objectsize += (rc > (100-objectsize)) ? (100-objectsize) : rc; icapsock.writeToSockete(data, rc, 0, o.content_scanner_timeout); sent += rc; } #ifdef DGDEBUG std::cout << "total sent to icap: " << sent << std::endl; #endif icapsock.writeString("\r\n0\r\n\r\n"); // end marker #ifdef DGDEBUG std::cout << "file was sent to icap" << std::endl; #endif } catch(std::exception & e) { #ifdef DGDEBUG std::cerr << "Exception sending file to ICAP: " << e.what() << std::endl; #endif lastmessage = "Exception sending file to ICAP"; syslog(LOG_ERR, "Exception sending file to ICAP: %s", e.what()); delete[]data; close(filefd); // this *might* just be an early response & closed connection if (icapsock.checkForInput()) { int rc = doScan(icapsock, docheader, object, objectsize, checkme); if (rc != ICAP_NODATA) return rc; } return DGCS_SCANERROR; } close(filefd); delete[] data; return doScan(icapsock, docheader, object, objectsize, checkme); }