diff --git a/src/XrdHttp/XrdHttpProtocol.cc b/src/XrdHttp/XrdHttpProtocol.cc index 0b24ab81f18..d917d0a430b 100644 --- a/src/XrdHttp/XrdHttpProtocol.cc +++ b/src/XrdHttp/XrdHttpProtocol.cc @@ -1065,10 +1065,10 @@ int XrdHttpProtocol::SendData(char *body, int bodylen) { /// Header_to_add is a set of header lines each CRLF terminated to be added to the header /// Returns 0 if OK -int XrdHttpProtocol::SendSimpleResp(int code, char *desc, char *header_to_add, char *body, int bodylen) { +int XrdHttpProtocol::SendSimpleResp(int code, char *desc, char *header_to_add, char *body, long long bodylen) { char outhdr[512]; char b[16]; - int l; + long long l; const char *crlf = "\r\n"; outhdr[0] = '\0'; @@ -1099,7 +1099,7 @@ int XrdHttpProtocol::SendSimpleResp(int code, char *desc, char *header_to_add, c else l = 0; } - sprintf(b, "%d", l); + sprintf(b, "%lld", l); strcat(outhdr, "Content-Length: "); strcat(outhdr, b); strncat(outhdr, crlf, 2); diff --git a/src/XrdHttp/XrdHttpProtocol.hh b/src/XrdHttp/XrdHttpProtocol.hh index d8956bc7fe0..bc6a122e86d 100644 --- a/src/XrdHttp/XrdHttpProtocol.hh +++ b/src/XrdHttp/XrdHttpProtocol.hh @@ -119,7 +119,7 @@ public: /// Sends a basic response. If the length is < 0 then it is calculated internally - int SendSimpleResp(int code, char *desc, char *header_to_add, char *body, int bodylen); + int SendSimpleResp(int code, char *desc, char *header_to_add, char *body, long long bodylen); private: diff --git a/src/XrdHttp/XrdHttpReq.cc b/src/XrdHttp/XrdHttpReq.cc index bdf60143f68..43add3a1baa 100644 --- a/src/XrdHttp/XrdHttpReq.cc +++ b/src/XrdHttp/XrdHttpReq.cc @@ -494,6 +494,10 @@ int XrdHttpReq::File(XrdXrootd::Bridge::Context &info, //!< the result context //prot->SendSimpleResp(200, NULL, NULL, NULL, dlen); int rc = info.Send(0, 0, 0, 0); TRACE(REQ, " XrdHttpReq::File dlen:" << dlen << " send rc:" << rc); + if (rc) return false; + writtenbytes += dlen; + + return true; }; @@ -813,34 +817,58 @@ int XrdHttpReq::ProcessHTTPReq() { return -1; } + // Prepare to chunk up the request + writtenbytes = 0; + // We want to be invoked again after this request is finished return 0; } } - case 2: // Read() + default: // Read() or Close() { + if ( ((reqstate == 3) && (rwOps.size() > 1)) || + (writtenbytes >= filesize) ) { + // Close() if this was a readv or we have finished, otherwise read the next chunk + + // --------- CLOSE + memset(&xrdreq, 0, sizeof (ClientRequest)); + xrdreq.close.requestid = htons(kXR_close); + memcpy(xrdreq.close.fhandle, fhandle, 4); + + if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) { + prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run close request.", 0); + return -1; + } + + // We have finished + return 1; + + } + if (rwOps.size() <= 1) { // No chunks or one chunk... Request the whole file or single read - + // // --------- READ memset(&xrdreq, 0, sizeof (xrdreq)); xrdreq.read.requestid = htons(kXR_read); memcpy(xrdreq.read.fhandle, fhandle, 4); xrdreq.read.dlen = 0; - + if (rwOps.size() == 0) { - xrdreq.read.offset = 0; - xrdreq.read.rlen = htonl(filesize); + long l = (long)min(filesize-writtenbytes, (long long)1024*1024); + xrdreq.read.offset = htonll(writtenbytes); + xrdreq.read.rlen = htonl(l); } else { - xrdreq.read.offset = htonll(rwOps[0].bytestart); - xrdreq.read.rlen = htonl(rwOps[0].byteend - rwOps[0].bytestart + 1); + long l = min(rwOps[0].byteend - rwOps[0].bytestart + 1 - writtenbytes, (long long)1024*1024); + xrdreq.read.offset = htonll(rwOps[0].bytestart + writtenbytes); + xrdreq.read.rlen = htonl(l); } - if (prot->ishttps) { + if (prot->ishttps) { if (!prot->Bridge->setSF((kXR_char *) fhandle, false)) { TRACE(REQ, " XrdBridge::SetSF(false) failed."); @@ -866,26 +894,7 @@ int XrdHttpReq::ProcessHTTPReq() { // We want to be invoked again after this request is finished return 0; } - case 3: // Close() - { - // --------- READ - memset(&xrdreq, 0, sizeof (ClientRequest)); - xrdreq.close.requestid = htons(kXR_close); - memcpy(xrdreq.close.fhandle, fhandle, 4); - - - if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) { - prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run close request.", 0); - return -1; - } - - // We have finished - - return 1; - - } - default: - return -1; + } @@ -1496,7 +1505,7 @@ int XrdHttpReq::PostProcessHTTPReq(bool final_) { if (rwOps.size() == 0) { - // Full file + // Full file. prot->SendSimpleResp(200, NULL, NULL, NULL, filesize); return 0; @@ -1544,8 +1553,11 @@ int XrdHttpReq::PostProcessHTTPReq(bool final_) { return -1; } } - case 2: //read + default: //read or readv { + // Close() if this was the third state of a readv, otherwise read the next chunk + if ((reqstate == 3) && (ntohs(xrdreq.header.requestid) == kXR_readv)) return 1; + // If we are here it's too late to send a proper error message... if (xrdresp == kXR_error) return -1; @@ -1599,21 +1611,13 @@ int XrdHttpReq::PostProcessHTTPReq(bool final_) { } else for (int i = 0; i < iovN; i++) { - prot->SendData((char *) iovP[i].iov_base, iovP[i].iov_len); + prot->SendData((char *) iovP[i].iov_base, iovP[i].iov_len); + writtenbytes += iovP[i].iov_len; } - + return 0; } - case 3: //close - { - return 1; - } - - - - default: - break; } diff --git a/src/XrdHttp/xrootd-http.cf b/src/XrdHttp/xrootd-http.cf index 5674911ba27..1baca955fcd 100644 --- a/src/XrdHttp/xrootd-http.cf +++ b/src/XrdHttp/xrootd-http.cf @@ -21,9 +21,9 @@ http.secretkey CHANGEME # As an example of preloading files, let's preload in memory # the /etc/services and /etc/hosts files # and assign them to some urlpaths in /static -http.staticpreload /static/services_preload1 /etc/services -http.staticpreload /static/services_preload2 /etc/services -http.staticpreload /static/hosts_preload /etc/hosts +#http.staticpreload /static/services_preload1 /etc/services +#http.staticpreload /static/services_preload2 /etc/services +#http.staticpreload /static/hosts_preload /etc/hosts # # Usual basic xrd stuff