From 298acf9a1a9e1f5224a2e10b69a8c7e4fa594237 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Sun, 19 Feb 2023 11:45:37 -0600 Subject: [PATCH 1/2] Denote Accept-Ranges in HEAD response Some clients (particularly, the golang library used by stashcp) will probe for byte range support by issuing a HEAD request and looking for the standard `Accept-Ranges` header in the response. Set this header in XrdHttp as we do support byte ranges. --- src/XrdHttp/XrdHttpReq.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/XrdHttp/XrdHttpReq.cc b/src/XrdHttp/XrdHttpReq.cc index ccd17a22781..448e060039b 100644 --- a/src/XrdHttp/XrdHttpReq.cc +++ b/src/XrdHttp/XrdHttpReq.cc @@ -1973,7 +1973,7 @@ int XrdHttpReq::PostProcessHTTPReq(bool final_) { if (m_req_digest.size()) { return 0; } else { - prot->SendSimpleResp(200, NULL, NULL, NULL, filesize, keepalive); + prot->SendSimpleResp(200, NULL, "Accept-Ranges: bytes", NULL, filesize, keepalive); return keepalive ? 1 : -1; } } @@ -1983,12 +1983,14 @@ int XrdHttpReq::PostProcessHTTPReq(bool final_) { return keepalive ? 1 : -1; } else { // We requested a checksum and now have its response. if (iovN > 0) { - std::string digest_response; - int response = PostProcessChecksum(digest_response); + std::string response_headers; + int response = PostProcessChecksum(response_headers); if (-1 == response) { return -1; } - prot->SendSimpleResp(200, NULL, digest_response.c_str(), NULL, filesize, keepalive); + if (!response_headers.empty()) {response_headers += "\r\n";} + response_headers += "Accept-Ranges: bytes"; + prot->SendSimpleResp(200, NULL, response_headers.c_str(), NULL, filesize, keepalive); return keepalive ? 1 : -1; } else { prot->SendSimpleResp(500, NULL, NULL, "Underlying filesystem failed to calculate checksum.", 0, false); From 0706303827cfcdeb83a902db69a577872cd56705 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Sun, 19 Feb 2023 11:47:15 -0600 Subject: [PATCH 2/2] Bugfix: Correct response for single byte range If an open-ended byte range is requested by the client: ``` Range: bytes=1234- ``` then the HTTP server was setting the end of the range to `-1`. In this case, once the file is opened, the end of the range should be set to `filesize - 1` (note ranges are inclusive of the end byte, meaning it looks like it's off-by-one -- that's just how the HTTP spec works). Without this, a single open-ended byte range request would fail. --- src/XrdHttp/XrdHttpReq.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/XrdHttp/XrdHttpReq.cc b/src/XrdHttp/XrdHttpReq.cc index 448e060039b..ef6177c89e7 100644 --- a/src/XrdHttp/XrdHttpReq.cc +++ b/src/XrdHttp/XrdHttpReq.cc @@ -2305,6 +2305,8 @@ int XrdHttpReq::PostProcessHTTPReq(bool final_) { } else if (rwOps.size() == 1) { // Only one read to perform + if (rwOps[0].byteend < 0) // The requested range was along the lines of "Range: 1234-", meaning we need to fill in the end + rwOps[0].byteend = filesize - 1; int cnt = (rwOps[0].byteend - rwOps[0].bytestart + 1); char buf[64]; @@ -2312,7 +2314,7 @@ int XrdHttpReq::PostProcessHTTPReq(bool final_) { sprintf(buf, "%lld-%lld/%lld", rwOps[0].bytestart, rwOps[0].byteend, filesize); s += buf; if (!m_digest_header.empty()) { - s += "\n"; + s += "\r\n"; s += m_digest_header.c_str(); }