Commit 37167bd9 authored by jan.koester's avatar jan.koester
Browse files

test urtl redir

parent a8c0eeb1
Loading
Loading
Loading
Loading
+138 −50
Original line number Diff line number Diff line
@@ -208,6 +208,15 @@ const std::string & libhttppp::HttpUrl::getPath() const{
libhttppp::HttpClient::HttpClient(const HttpUrl& desturl)
: _url(desturl){
    try {
    resetConnection();
    } catch (netplus::NetException &e) {
        HTTPException ex;
        ex[HTTPException::Error] << "HttpClient ctor connect failed: " << e.what();
        throw ex; // !!! IMPORTANT: throw HTTPException, nicht NetException
    }
}

void libhttppp::HttpClient::resetConnection(){
  if (_url.getProtocol() == HttpUrl::HTTPS) {
    std::map<std::string, netplus::ssl::CertificateBundle> certs;
    auto sslsock = std::make_unique<netplus::ssl>(certs,-1);
@@ -229,14 +238,9 @@ libhttppp::HttpClient::HttpClient(const HttpUrl& desturl)
    _isH2 = (alpn == "h2");
    std::cerr << "[HttpClient] ALPN negotiated: '" << alpn << "' isH2=" << _isH2 << std::endl;
  } else {
    _isH2 = false;
    std::cerr << "[HttpClient] Not an SSL socket" << std::endl;
  }

    } catch (netplus::NetException &e) {
        HTTPException ex;
        ex[HTTPException::Error] << "HttpClient ctor connect failed: " << e.what();
        throw ex; // !!! IMPORTANT: throw HTTPException, nicht NetException
    }
}


@@ -256,6 +260,31 @@ static inline void sleep_note() {
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
}

static bool is_redirect_status(int code) {
  return code == 301 || code == 302 || code == 303 || code == 307 || code == 308;
}

static std::string extract_location_from_response(const libhttppp::HttpResponse &res) {
  auto *hd = res.getHeaderData("location");
  if (!hd) return {};
  auto *v = hd->getfirstValue();
  if (!v) return {};
  return v->getvalue();
}

static std::string normalize_path(const std::string &location, const std::string &base_path) {
  if (location.empty()) return base_path.empty() ? std::string("/") : base_path;
  if (location[0] == '/') return location;
  if (location[0] == '?') {
    std::string base = base_path.empty() ? std::string("/") : base_path;
    return base + location;
  }
  std::string base = base_path.empty() ? std::string("/") : base_path;
  size_t slash = base.find_last_of('/');
  if (slash == std::string::npos) return std::string("/") + location;
  return base.substr(0, slash + 1) + location;
}

// --------------- HTTP/2 client frame helpers ---------------
static constexpr uint8_t H2C_FRAME_DATA         = 0x00;
static constexpr uint8_t H2C_FRAME_HEADERS      = 0x01;
@@ -365,18 +394,20 @@ const std::vector<char> libhttppp::HttpClient::_h2Request(
        auth << _url.getHost() << ":" << _url.getPort();

        // Collect extra headers from the request
        bool has_content_length = false;
        std::vector<hpack::HeaderField> extra;
        for (HttpHeader::HeaderData *hd = nreq.getfirstHeaderData(); hd; hd = hd->nextHeaderData()) {
            const std::string &key = hd->getkey();
            if (key.empty() || key[0] == ':') continue;
            if (key == "host") continue; // :authority replaces host in H2
          if (key == "content-length") has_content_length = true;
            for (HttpHeader::HeaderData::Values *v = hd->getfirstValue(); v; v = v->nextvalue()) {
                extra.push_back({key, v->getvalue(), false});
            }
        }

        // Add content-length for POST body (servers may rely on it)
        if (postBody && !postBody->empty()) {
        if (postBody && !has_content_length) {
          extra.push_back({"content-length", std::to_string(postBody->size()), false});
        }

@@ -521,6 +552,13 @@ const std::vector<char> libhttppp::HttpClient::_h2Request(

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

    try {
        const int kMaxRedirects = 1;
        int redirects = 0;

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

@@ -535,9 +573,6 @@ const std::vector<char> libhttppp::HttpClient::Get(libhttppp::HttpRequest &nreq)
                return _h2Request("GET", nreq);
            }

    std::vector<char> ret;

    try {
        // ---------------------------------------------------------
        // 0) Build request headers
        // ---------------------------------------------------------
@@ -614,6 +649,23 @@ const std::vector<char> libhttppp::HttpClient::Get(libhttppp::HttpRequest &nreq)
            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;
          }
        }

        // bytes after header already read
        size_t body_off = parsed_hsize;
        size_t body_avail = raw.size() - body_off;
@@ -808,6 +860,8 @@ const std::vector<char> libhttppp::HttpClient::Get(libhttppp::HttpRequest &nreq)

        return ret;

        }

    } catch (netplus::NetException &e) {
        libhttppp::HTTPException ee;
        ee[libhttppp::HTTPException::Error] << e.what();
@@ -818,14 +872,13 @@ const std::vector<char> libhttppp::HttpClient::Get(libhttppp::HttpRequest &nreq)
const std::vector<char> libhttppp::HttpClient::Post(libhttppp::HttpRequest &nreq,
                                                    const std::vector<char> &post)
{
    // HTTP/2: delegate to binary framing path
    if (_isH2) {
        return _h2Request("POST", nreq, &post);
    }

    std::vector<char> ret;

    try {
    const int kMaxRedirects = 1;
    int redirects = 0;

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

@@ -836,12 +889,18 @@ const std::vector<char> libhttppp::HttpClient::Post(libhttppp::HttpRequest &nreq
        if (nreq.getRequestVersion().empty())
          nreq.setRequestVersion(HTTPVERSION(1.1));

        // Always send content-length for POST body
        nreq.setHeaderData("content-length")->push_back(std::to_string(post.size()));

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

        // Debug logging
        std::cerr << "[HttpClient::Post] URL path: '" << nreq.getRequestURL() 
                  << "' | POST body size: " << post.size() << std::endl;

        // IMPORTANT: length as string
        nreq.setHeaderData("content-length")->push_back(std::to_string(post.size()));
        // (optionally) set content-type:
        // nreq.setHeaderData("Content-Type")->push_back("application/json");

@@ -923,6 +982,23 @@ const std::vector<char> libhttppp::HttpClient::Post(libhttppp::HttpRequest &nreq
            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;

        // ---------------------------------------------------------
@@ -1099,13 +1175,13 @@ const std::vector<char> libhttppp::HttpClient::Post(libhttppp::HttpRequest &nreq
            std::cerr << "[HttpClient::Post] Response first 200 bytes: " 
                      << std::string(ret.begin(), ret.begin() + 200) << std::endl;
        }
          return ret;
        }
    } catch (netplus::NetException &e) {
        libhttppp::HTTPException ee;
        ee[libhttppp::HTTPException::Error] << e.what();
        throw ee;
    }

    return ret;
}

int libhttppp::HttpClient::readchunk(const char *data, int datasize, int &pos)
@@ -1465,6 +1541,7 @@ libhttppp::HttpHeader::HeaderData::Values::Values(const Values& val)

libhttppp::HttpResponse::HttpResponse() : HttpHeader(){
  setState(HTTP200);
  _StatusCode = 200;
  _ContentType=nullptr;
  _ContentLength=setHeaderData("content-length");
  _ContentLength->push_back(0);
@@ -1474,6 +1551,9 @@ libhttppp::HttpResponse::HttpResponse() : HttpHeader(){
}

libhttppp::HttpResponse::HttpResponse(const HttpResponse &src) : HttpResponse(){
  _State = src._State;
  _Version = src._Version;
  _StatusCode = src._StatusCode;
  for(HttpHeader::HeaderData *curdat=src._firstHeaderData.get(); curdat; curdat=curdat->nextHeaderData()){
    HttpHeader::HeaderData  *newdat=setHeaderData(curdat->getkey());
    for(HttpHeader::HeaderData::Values *curval=curdat->getfirstValue(); curval; curval=curval->nextvalue()){
@@ -1515,6 +1595,10 @@ const std ::string &libhttppp::HttpResponse::getState() const{
  return _State;
}

int libhttppp::HttpResponse::getStatusCode() const{
  return _StatusCode;
}

size_t libhttppp::HttpResponse::getContentLength() const{
  if(!_ContentLength || _ContentLength->empty())
    return 0;
@@ -1797,7 +1881,11 @@ size_t libhttppp::HttpResponse::parse(const char *data, size_t inlen) {
        v_end = status_line.length();
    }
    std::string status_code_str = status_line.substr(v_start, v_end - v_start);
    // you might want to convert this to int, but I'm leaving your original logic
    try {
      _StatusCode = std::stoi(status_code_str);
    } catch (...) {
      _StatusCode = 0;
    }

    // reason phrase
    v_start = v_end + 1;
+3 −0
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ namespace libhttppp {
      const std::vector<char> Get(HttpRequest &nreq);
      const std::vector<char> Post(HttpRequest &nreq,const std::vector<char> &post);
  private:
      void resetConnection();
      int readchunk(const char *data,int datasize,int &pos);

      // HTTP/2 client helpers
@@ -196,6 +197,7 @@ namespace libhttppp {

    /*client methods*/
    const std ::string &getState() const;
    int                getStatusCode() const;
    const std ::string &getContentType() const;
    size_t              getContentLength() const;
    const std ::string &getConnection() const;
@@ -217,6 +219,7 @@ namespace libhttppp {

    std::string      _State=HTTP200;
    std::string      _Version;
    int              _StatusCode=200;
    HeaderData      *_TransferEncoding;
    HeaderData      *_Connection;
    HeaderData      *_ContentType;