Commit e7fadcd9 authored by jan.koester's avatar jan.koester
Browse files

delete implement

parent 26347eb6
Loading
Loading
Loading
Loading
+302 −1
Original line number Diff line number Diff line
@@ -1228,6 +1228,305 @@ const std::vector<char> libhttppp::HttpClient::Post(libhttppp::HttpRequest &nreq
    }
}

const std::vector<char> libhttppp::HttpClient::Delete(libhttppp::HttpRequest &nreq)
{
    std::vector<char> ret;

    try {
        // Ensure a fresh connection for each request; keep-alive reuse
        // is unreliable without full connection-state tracking.
        resetConnection();

        const int kMaxRedirects = 1;
        int redirects = 0;

        for (;;) {
            std::stringstream host;
            host << _url.getHost() << ":" << _url.getPort();

            nreq.setHeaderData("host")->push_back(host.str());
            nreq.setRequestType(DELETEREQUEST);

            if (nreq.getRequestURL().empty())
                nreq.setRequestURL(_url.getPath());

            // HTTP/2: delegate to binary framing path
            if (_isH2) {
                return _h2Request("DELETE", nreq);
            }

        // ---------------------------------------------------------
        // 0) Build request headers
        // ---------------------------------------------------------
        if (nreq.getRequestVersion().empty())
            nreq.setRequestVersion(HTTPVERSION(1.1));

        // ---------------------------------------------------------
        // 1) Send request
        // ---------------------------------------------------------
        nreq.send(_url, _cltsock);

        // ---------------------------------------------------------
        // helper: recv one chunk with Note-retry
        // ---------------------------------------------------------
        auto recv_blocking = [&](netplus::buffer& b) -> size_t {
            for (;;) {
                try {
                    size_t n = _cltsock->recvData(b, 0);
                    return n;
                } catch (netplus::NetException& e) {
                    if (e.getErrorType() == netplus::NetException::Note) {
                        sleep_note();
                        continue;
                    }
                    throw;
                }
            }
        };

        // ---------------------------------------------------------
        // 2) Read until we have full header (\r\n\r\n)
        // ---------------------------------------------------------
        std::vector<char> raw;
        raw.reserve(8192);

        size_t header_end = std::string::npos;

        for (;;) {
            if (raw.size() >= 4) {
                for (size_t i = 0; i + 3 < raw.size(); ++i) {
                    if (raw[i] == '\r' && raw[i+1] == '\n' &&
                        raw[i+2] == '\r' && raw[i+3] == '\n')
                    {
                        header_end = i + 4;
                        break;
                    }
                }
            }
            if (header_end != std::string::npos)
                break;

            netplus::buffer buf(BLOCKSIZE);
            size_t n = recv_blocking(buf);
            if (n == 0) {
                netplus::NetException ne;
                ne[netplus::NetException::Error] << "HTTP DELETE: EOF while reading header";
                throw ne;
            }
            raw.insert(raw.end(), buf.data.buf, buf.data.buf + n);
        }

        // ---------------------------------------------------------
        // 3) Parse header
        // ---------------------------------------------------------
        libhttppp::HttpResponse res;
        size_t parsed_hsize = res.parse(raw.data(), raw.size());

        if (parsed_hsize == 0 || parsed_hsize > raw.size()) {
            libhttppp::HTTPException he;
            he[libhttppp::HTTPException::Error] << "HTTP DELETE: response header parse failed";
            throw he;
        }

        if (is_redirect_status(res.getStatusCode()) && redirects < kMaxRedirects) {
          std::string location = extract_location_from_response(res);
          if (!location.empty()) {
            ++redirects;
            if (location.rfind("http://", 0) == 0 || location.rfind("https://", 0) == 0) {
              _url = HttpUrl(location, false);
              nreq.setRequestURL(_url.getPath());
            } else {
              std::string base = nreq.getRequestURL().empty() ? _url.getPath() : nreq.getRequestURL();
              nreq.setRequestURL(normalize_path(location, base));
            }

            resetConnection();
            continue;
          }
        }

        size_t body_off = parsed_hsize;

        // ---------------------------------------------------------
        // 4) Determine transfer mode
        // ---------------------------------------------------------
        bool chunked = false;
        ptrdiff_t content_len = -1;

        try {
            for (libhttppp::HttpHeader::HeaderData::Values *v = res.getTransferEncoding();
                 v; v = v->nextvalue())
            {
                std::string val = tolower_copy(v->getvalue());
                if (val == "chunked") {
                    chunked = true;
                    break;
                }
            }
        } catch (...) {
            // ignore
        }

        if (!chunked) {
            try {
                content_len = res.getContentLength();
                if (content_len < 0) content_len = -1;
            } catch (...) {
                content_len = -1;
            }
        }

        // ---------------------------------------------------------
        // 5) Helper: append from raw buffer
        // ---------------------------------------------------------
        auto append_from_raw = [&](size_t& take_pos, size_t take_len) {
            if (take_len == 0) return;
            ret.insert(ret.end(), raw.begin() + (ptrdiff_t)take_pos,
                                  raw.begin() + (ptrdiff_t)(take_pos + take_len));
            take_pos += take_len;
        };

        // =========================================================
        // 6A) BODY: Content-Length
        // =========================================================
        if (!chunked && content_len >= 0) {
            size_t remaining = (size_t)content_len;
            size_t pos = body_off;

            size_t can = (std::min)(remaining, raw.size() - pos);
            append_from_raw(pos, can);
            remaining -= can;

            while (remaining > 0) {
                netplus::buffer buf(BLOCKSIZE);
                size_t n = recv_blocking(buf);
                if (n == 0) {
                    netplus::NetException ne;
                    ne[netplus::NetException::Error] << "HTTP DELETE: EOF before Content-Length complete";
                    throw ne;
                }
                size_t take = (std::min)(remaining, n);
                ret.insert(ret.end(), buf.data.buf, buf.data.buf + take);
                remaining -= take;
            }
            return ret;
        }

        // =========================================================
        // 6B) BODY: chunked
        // =========================================================
        if (chunked) {
            size_t pos = body_off;

            auto ensure_bytes = [&](size_t need) {
                while (raw.size() - pos < need) {
                    netplus::buffer buf(BLOCKSIZE);
                    size_t n = recv_blocking(buf);
                    if (n == 0) {
                        netplus::NetException ne;
                        ne[netplus::NetException::Error] << "HTTP DELETE: EOF while reading chunked body";
                        throw ne;
                    }
                    raw.insert(raw.end(), buf.data.buf, buf.data.buf + n);
                }
            };

            auto read_line = [&]() -> std::string {
                for (;;) {
                    for (size_t i = pos; i + 1 < raw.size(); ++i) {
                        if (raw[i] == '\r' && raw[i+1] == '\n') {
                            std::string line(raw.begin() + (ptrdiff_t)pos,
                                             raw.begin() + (ptrdiff_t)i);
                            pos = i + 2;
                            return line;
                        }
                    }
                    netplus::buffer buf(BLOCKSIZE);
                    size_t n = recv_blocking(buf);
                    if (n == 0) {
                        netplus::NetException ne;
                        ne[netplus::NetException::Error] << "HTTP DELETE: EOF while reading chunk size line";
                        throw ne;
                    }
                    raw.insert(raw.end(), buf.data.buf, buf.data.buf + n);
                }
            };

            for (;;) {
                std::string szline = read_line();
                auto sem = szline.find(';');
                if (sem != std::string::npos) szline.resize(sem);

                size_t chunk_size = 0;
                try {
                    chunk_size = (size_t)std::stoul(szline, nullptr, 16);
                } catch (...) {
                    libhttppp::HTTPException he;
                    he[libhttppp::HTTPException::Error] << "HTTP DELETE: invalid chunk size line: " << szline;
                    throw he;
                }

                if (chunk_size == 0) {
                    for (;;) {
                        std::string tline = read_line();
                        if (tline.empty())
                            break;
                    }
                    break;
                }

                ensure_bytes(chunk_size + 2);

                ret.insert(ret.end(),
                           raw.begin() + (ptrdiff_t)pos,
                           raw.begin() + (ptrdiff_t)(pos + chunk_size));
                pos += chunk_size;

                if (raw[pos] != '\r' || raw[pos+1] != '\n') {
                    libhttppp::HTTPException he;
                    he[libhttppp::HTTPException::Error] << "HTTP DELETE: bad chunk terminator";
                    throw he;
                }
                pos += 2;
            }

            return ret;
        }

        // =========================================================
        // 6C) BODY: no length, not chunked -> read until EOF
        // =========================================================
        {
            size_t pos = body_off;

            if (raw.size() > pos) {
                ret.insert(ret.end(), raw.begin() + (ptrdiff_t)pos, raw.end());
            }

            for (;;) {
                netplus::buffer buf(BLOCKSIZE);
                size_t n = 0;
                try {
                    n = recv_blocking(buf);
                } catch (...) {
                    throw;
                }
                if (n == 0) break;
                ret.insert(ret.end(), buf.data.buf, buf.data.buf + n);
            }
        }

        return ret;

        }

    } catch (netplus::NetException &e) {
        libhttppp::HTTPException ee;
        ee[libhttppp::HTTPException::Error] << e.what();
        throw ee;
    }
}

int libhttppp::HttpClient::readchunk(const char *data, int datasize, int &pos)
{
    // 1) Skip CRLF left after previous chunk
@@ -2437,6 +2736,8 @@ void libhttppp::HttpRequest::printHeader(std::string &buffer){
    buffer="GET ";
  else if(_RequestType==POSTREQUEST)
    buffer="POST ";
  else if(_RequestType==DELETEREQUEST)
    buffer="DELETE ";

  buffer.append(_cachedRequest);
  buffer.append(" ");
@@ -2569,7 +2870,7 @@ void libhttppp::HttpRequest::send(const HttpUrl &dest,
}

void libhttppp::HttpRequest::setRequestType(int req){
  if(req == POSTREQUEST || req == GETREQUEST){
  if(req == POSTREQUEST || req == GETREQUEST || req == DELETEREQUEST){
    _RequestType=req;
    return;
  }