bool CetonStreamHandler::HttpRequest( const QString &method, const QString &script, const QUrl ¶ms, QString &response, uint &status_code) const { QHttp http; http.setHost(_ip_address); QByteArray request_params(params.encodedQuery()); if (method == "GET") { QString path = script + "?" + QString(request_params); QHttpRequestHeader header(method, path); header.setValue("Host", _ip_address); http.request(header); } else { QHttpRequestHeader header(method, script); header.setValue("Host", _ip_address); header.setContentType("application/x-www-form-urlencoded"); http.request(header, request_params); } while (http.hasPendingRequests() || http.currentId()) { usleep(5000); qApp->processEvents(); } if (http.error() != QHttp::NoError) { status_code = 0; response = http.errorString(); return false; } QHttpResponseHeader resp_header = http.lastResponse(); if (!resp_header.isValid()) { status_code = 0; response = "Completed but response object was not valid"; return false; } status_code = resp_header.statusCode(); response = QString(http.readAll()); return true; }
// do a multi-range on selected ranges MultirangeResult HttpIOVecOps::performMultirange(IOChainContext & iocontext, const IntervalTree<ElemChunk> &tree, const SortedRanges & ranges) { DavixError * tmp_err=NULL; dav_ssize_t tmp_ret=-1, ret = 0; ptrdiff_t p_diff=0; dav_size_t counter = 0; MultirangeResult::OperationResult opresult = MultirangeResult::SUCCESS; // calculate total bytes to be read (approximate, since ranges could overlap) dav_ssize_t bytes_to_read = 0; for(dav_size_t i = 0; i < ranges.size(); i++) { bytes_to_read += (ranges[i].second - ranges[i].first + 1); } std::function<int (dav_off_t &, dav_off_t &)> offsetProvider = std::bind(&davIOVecProvider, ranges, std::ref(counter), std::placeholders::_1, std::placeholders::_2); // header line need to be inferior to 8K on Apache2 / ngnix // in Addition, some S3 implementation limit the total header size to 4k.... // 3900 bytes maximum for the range seems to be a ood compromise std::vector< std::pair<dav_size_t, std::string> > vecRanges = generateRangeHeaders(3900, offsetProvider); DAVIX_SLOG(DAVIX_LOG_DEBUG, DAVIX_LOG_CHAIN, " -> getPartialVec operation for {} vectors", ranges.size()); for(std::vector< std::pair<dav_size_t, std::string> >::iterator it = vecRanges.begin(); it < vecRanges.end(); ++it){ DAVIX_SLOG(DAVIX_LOG_DEBUG, DAVIX_LOG_CHAIN, " -> getPartialVec request for {} chunks", it->first); if(it->first == 1){ // one chunk only : no need of multi part ret += singleRangeRequest(iocontext, tree, ranges[p_diff].first, ranges[p_diff].second - ranges[p_diff].first + 1); p_diff += 1; }else{ GetRequest req (iocontext._context, iocontext._uri, &tmp_err); if(tmp_err == NULL){ RequestParams request_params(iocontext._reqparams); req.setParameters(request_params); req.addHeaderField(req_header_byte_range, it->second); if( req.beginRequest(&tmp_err) == 0){ const int retcode = req.getRequestCode(); // looks like the server supports multi-range requests.. yay if(retcode == 206) { ret = parseMultipartRequest(req, tree, &tmp_err); // could not parse multipart response - server's broken? // known to happen with ceph - return code is 206, but only // returns the first range if(ret == -1) { opresult = MultirangeResult::NOMULTIRANGE; req.endRequest(&tmp_err); break; } } // no multi-range.. bad server, bad else if(retcode == 200) { DAVIX_SLOG(DAVIX_LOG_DEBUG, DAVIX_LOG_CHAIN, "Multi-range request resulted in getting the whole file."); // we have two options: read the entire file or abort current // request and start a multi-range simulation // if this is a huge file, reading the entire contents is // definitely not an option if(req.getAnswerSize() > 1000000 && req.getAnswerSize() > 2*bytes_to_read) { DAVIX_SLOG(DAVIX_LOG_DEBUG, DAVIX_LOG_CHAIN, "File is too large; will not waste bandwidth, bailing out"); opresult = MultirangeResult::NOMULTIRANGE; req.endRequest(&tmp_err); } else { DAVIX_SLOG(DAVIX_LOG_DEBUG, DAVIX_LOG_CHAIN, "Simulating multi-part response from the contents of the entire file"); opresult = MultirangeResult::SUCCESS_BUT_NO_MULTIRANGE; ret = simulateMultiPartRequest(req, tree, &tmp_err); } break; } else if(retcode == 416) { ret = 0; DavixError::clearError(&tmp_err); } else { httpcodeToDavixError(req.getRequestCode(),davix_scope_http_request(),", ", &tmp_err); ret = -1; break; } p_diff += it->first; ret += tmp_ret; } else { ret = -1; break; } } } } DAVIX_SLOG(DAVIX_LOG_DEBUG, DAVIX_LOG_CHAIN, " <- getPartialVec operation for {} vectors", ranges.size()); checkDavixError(&tmp_err); return MultirangeResult(opresult, ret); }