Commit 46158096 authored by Jan Koester's avatar Jan Koester
Browse files

dav

parent ab452b00
Loading
Loading
Loading
Loading
+72 −46
Changes for src/http.cpp: 72 added lines, 46 removed lines.
Original line number Diff line number Diff line
@@ -3251,6 +3251,60 @@ const std::vector<char> libhttppp::HttpClient::_doH1Request(
    }
}

int libhttppp::RequestTypeFromMethod(const std::string &method)
{
    static const std::map<std::string, int> kTypes = {
        {"GET", GETREQUEST},           {"POST", POSTREQUEST},
        {"PUT", PUTREQUEST},           {"DELETE", DELETEREQUEST},
        {"OPTIONS", OPTIONSREQUEST},   {"HEAD", HEADREQUEST},
        {"PATCH", PATCHREQUEST},       {"PROPFIND", PROPFINDREQUEST},
        {"PROPPATCH", PROPPATCHREQUEST}, {"MKCOL", MKCOLREQUEST},
        {"COPY", COPYREQUEST},         {"MOVE", MOVEREQUEST},
        {"LOCK", LOCKREQUEST},         {"UNLOCK", UNLOCKREQUEST},
        {"REPORT", REPORTREQUEST},     {"SEARCH", SEARCHREQUEST},
    };
    auto it = kTypes.find(method);
    return it != kTypes.end() ? it->second : GETREQUEST;
}

const char *libhttppp::RequestMethodName(int requestType)
{
    switch (requestType) {
        case GETREQUEST: return "GET";
        case POSTREQUEST: return "POST";
        case PUTREQUEST: return "PUT";
        case DELETEREQUEST: return "DELETE";
        case OPTIONSREQUEST: return "OPTIONS";
        case HEADREQUEST: return "HEAD";
        case PATCHREQUEST: return "PATCH";
        case PROPFINDREQUEST: return "PROPFIND";
        case PROPPATCHREQUEST: return "PROPPATCH";
        case MKCOLREQUEST: return "MKCOL";
        case COPYREQUEST: return "COPY";
        case MOVEREQUEST: return "MOVE";
        case LOCKREQUEST: return "LOCK";
        case UNLOCKREQUEST: return "UNLOCK";
        case REPORTREQUEST: return "REPORT";
        case SEARCHREQUEST: return "SEARCH";
        default: return "";
    }
}

const std::vector<char> libhttppp::HttpClient::Request(int requestType, libhttppp::HttpRequest &nreq,
                                                       const std::vector<char> *body, size_t maxTries)
{
    const char *method = RequestMethodName(requestType);
    if (!*method) {
        HTTPException excep;
        excep[HTTPException::Error] << "HttpClient::Request: unknown request type " << requestType;
        throw excep;
    }
    // Generic entry point for methods without a dedicated wrapper (WebDAV etc.); like
    // Delete()/Options(), doesn't chase redirects -- a 3xx to PROPFIND/MOVE/... belongs
    // to the caller.
    return _doH1Request(method, requestType, nreq, body, maxTries, /*followRedirects=*/false);
}

const std::vector<char> libhttppp::HttpClient::Get(libhttppp::HttpRequest &nreq, size_t maxTries)
{
    return _doH1Request("GET", GETREQUEST, nreq, nullptr, maxTries, /*followRedirects=*/true);
@@ -4319,14 +4373,7 @@ size_t libhttppp::HttpRequest::parseH2(const std::vector<hpack::HeaderField> &he
  // Derive cached fields and request type from stored headers
  auto *methodHd = getHeaderData(":method");
  std::string method = (methodHd && methodHd->getfirstValue()) ? methodHd->getfirstValue()->getvalue() : "GET";
  if (method == "GET")          _RequestType = GETREQUEST;
  else if (method == "POST")    _RequestType = POSTREQUEST;
  else if (method == "PUT")     _RequestType = PUTREQUEST;
  else if (method == "DELETE")  _RequestType = DELETEREQUEST;
  else if (method == "OPTIONS") _RequestType = OPTIONSREQUEST;
  else if (method == "HEAD")    _RequestType = HEADREQUEST;
  else if (method == "PATCH")   _RequestType = PATCHREQUEST;
  else                          _RequestType = GETREQUEST;
  _RequestType = RequestTypeFromMethod(method);

  auto *pathHd = getHeaderData(":path");
  std::string path = (pathHd && pathHd->getfirstValue()) ? pathHd->getfirstValue()->getvalue() : "/";
@@ -4398,14 +4445,7 @@ size_t libhttppp::HttpRequest::parseH3(const std::vector<qpack::HeaderField> &he
  // Derive cached fields and request type from stored headers
  auto *methodHd = getHeaderData(":method");
  std::string method = (methodHd && methodHd->getfirstValue()) ? methodHd->getfirstValue()->getvalue() : "GET";
  if (method == "GET")          _RequestType = GETREQUEST;
  else if (method == "POST")    _RequestType = POSTREQUEST;
  else if (method == "PUT")     _RequestType = PUTREQUEST;
  else if (method == "DELETE")  _RequestType = DELETEREQUEST;
  else if (method == "OPTIONS") _RequestType = OPTIONSREQUEST;
  else if (method == "HEAD")    _RequestType = HEADREQUEST;
  else if (method == "PATCH")   _RequestType = PATCHREQUEST;
  else                          _RequestType = GETREQUEST;
  _RequestType = RequestTypeFromMethod(method);

  auto *pathHd = getHeaderData(":path");
  std::string path = (pathHd && pathHd->getfirstValue()) ? pathHd->getfirstValue()->getvalue() : "/";
@@ -4500,19 +4540,13 @@ size_t libhttppp::HttpRequest::parseH1() {
    }

    // 5) Set request type
    if (method == "GET")          _RequestType = GETREQUEST;
    else if (method == "POST")    _RequestType = POSTREQUEST;
    else if (method == "PUT")     _RequestType = PUTREQUEST;
    else if (method == "DELETE")  _RequestType = DELETEREQUEST;
    else if (method == "OPTIONS") _RequestType = OPTIONSREQUEST;
    else if (method == "HEAD")    _RequestType = HEADREQUEST;
    else if (method == "PATCH")   _RequestType = PATCHREQUEST;
    // Anything else falling back to PARSEREQUEST was worse than just wrong labeling: the
    // REQUESTHANDLING switch in httpd.cpp only recognizes GET/POST/PUT/DELETE/PARSEREQUEST,
    // and PARSEREQUEST there means "re-invoke parse() on whatever's left in RecvData" -- for
    // an already-fully-parsed-but-unrecognized method that reparses the request body (or
    // nothing) as a fresh request line, never reaching RequestEvent at all.
    else                          _RequestType = GETREQUEST;
    // Unrecognized methods map to GETREQUEST inside RequestTypeFromMethod rather than
    // PARSEREQUEST: the REQUESTHANDLING switch in httpd.cpp treats PARSEREQUEST as
    // "re-invoke parse() on whatever's left in RecvData" -- for an already-fully-parsed-but-
    // unrecognized method that reparses the request body (or nothing) as a fresh request
    // line, never reaching RequestEvent at all. The original method string stays available
    // via getRequestMethod() (":method" pseudo-header) either way.
    _RequestType = RequestTypeFromMethod(method);

    // 6) Store pseudo-headers in _firstHeaderData (unified storage)
    {
@@ -4647,21 +4681,8 @@ size_t libhttppp::HttpRequest::parseH1() {
}

void libhttppp::HttpRequest::printHeader(std::string &buffer){
  if(_RequestType==GETREQUEST)
    buffer="GET ";
  else if(_RequestType==POSTREQUEST)
    buffer="POST ";
  else if(_RequestType==PUTREQUEST)
    buffer="PUT ";
  else if(_RequestType==DELETEREQUEST)
    buffer="DELETE ";
  else if(_RequestType==OPTIONSREQUEST)
    buffer="OPTIONS ";
  else if(_RequestType==HEADREQUEST)
    buffer="HEAD ";
  else if(_RequestType==PATCHREQUEST)
    buffer="PATCH ";

  buffer=RequestMethodName(_RequestType);
  buffer.append(" ");
  buffer.append(_cachedRequest);
  buffer.append(" ");
  buffer.append(_cachedRequestVersion);
@@ -4711,6 +4732,12 @@ int libhttppp::HttpRequest::getRequestType(){
  return _RequestType;
}

std::string libhttppp::HttpRequest::getRequestMethod(){
  if (auto *hd = getHeaderData(":method"))
    if (auto *v = hd->getfirstValue()) return v->getvalue();
  return RequestMethodName(_RequestType);
}

const std::string &libhttppp::HttpRequest::getRequestURL(){
  if (_cachedRequestURL.empty() && !_cachedRequest.empty()) {
    _cachedRequestURL = extractPath(_cachedRequest);
@@ -4951,8 +4978,7 @@ void libhttppp::HttpRequest::send(const HttpUrl &dest,
}

void libhttppp::HttpRequest::setRequestType(int req){
  if(req == POSTREQUEST || req == GETREQUEST || req == PUTREQUEST || req == DELETEREQUEST ||
     req == OPTIONSREQUEST || req == HEADREQUEST || req == PATCHREQUEST){
  if(*RequestMethodName(req)){
    _RequestType=req;
    return;
  }
+12 −0
Changes for src/http.h: 12 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -51,6 +51,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace libhttppp::qpack { struct HeaderField; }

namespace libhttppp {
  // Method token <-> *REQUEST constant (httpdefinitions.h). Unknown methods map to
  // GETREQUEST; RequestMethodName returns "" for an unknown type.
  int RequestTypeFromMethod(const std::string &method);
  const char *RequestMethodName(int requestType);

  class HttpRequest;

  class HttpUrl {
@@ -129,6 +134,10 @@ namespace libhttppp {
      const std::vector<char> Options(HttpRequest &nreq, size_t maxTries=0);
      const std::vector<char> Head(HttpRequest &nreq, size_t maxTries=0);
      const std::vector<char> Patch(HttpRequest &nreq,const std::vector<char> &patch, size_t maxTries=0);
      // Any method known to RequestTypeFromMethod (e.g. PROPFIND, MKCOL, MOVE for WebDAV);
      // body may be nullptr. Never follows redirects.
      const std::vector<char> Request(int requestType, HttpRequest &nreq,
                                      const std::vector<char> *body = nullptr, size_t maxTries=0);

      // Streaming API: send request, return parsed response headers only.
      // After this call, use readBodyChunk() to read body data incrementally.
@@ -495,6 +504,9 @@ namespace libhttppp {

    void                      printHeader(std::string &buffer);
    int                         getRequestType();
    // Original method token as received (":method"), e.g. "PROPFIND" -- unlike
    // getRequestType() this survives methods unknown to RequestTypeFromMethod.
    std::string                 getRequestMethod();
    const std::string &getRequestURL();
    const std::string &getRequest();
    size_t                    getRequestLength();
+16 −3
Changes for src/httpd.cpp: 16 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -2252,7 +2252,19 @@ REQUESTHANDLING:
                _dispatchH1Request(cureq, 0, tid, args);
                break;
            case PUTREQUEST:
            case PATCHREQUEST: {
            case PATCHREQUEST:
            // WebDAV: PROPFIND/PROPPATCH/LOCK/REPORT/SEARCH carry XML bodies, MKCOL may;
            // COPY/MOVE/UNLOCK normally don't, but waiting on Content-Length/chunked is
            // harmless when there's none (clen==0 dispatches immediately).
            case PROPFINDREQUEST:
            case PROPPATCHREQUEST:
            case MKCOLREQUEST:
            case COPYREQUEST:
            case MOVEREQUEST:
            case LOCKREQUEST:
            case UNLOCKREQUEST:
            case REPORTREQUEST:
            case SEARCHREQUEST: {
                if(cureq.isChunkedRequest()){
                    int dr = cureq.decodeChunkedBody();
                    if(dr == 0) break;          // body incomplete, wait for more
@@ -2428,8 +2440,9 @@ void libhttppp::HttpEvent::ResponseEvent(netplus::con &curcon,const int tid,ULON
        // destroy parsed headers — including Content-Length — causing the
        // partially received body to be re-parsed as HTTP headers, which
        // leads to an endless loop for large/multi-file uploads).
        if (cureq.getRequestType() == POSTREQUEST || cureq.getRequestType() == PUTREQUEST ||
            cureq.getRequestType() == PATCHREQUEST) {
        const int rt = cureq.getRequestType();
        if (rt == POSTREQUEST || rt == PUTREQUEST || rt == PATCHREQUEST ||
            (rt >= PROPFINDREQUEST && rt <= SEARCHREQUEST)) {
            return;
        }
        if (cureq.getRequestType() == PARSEREQUEST && cureq.getRequestURL().empty()) {
+11 −0
Changes for src/httpdefinitions.h: 11 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -36,6 +36,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define OPTIONSREQUEST 5
#define HEADREQUEST    6
#define PATCHREQUEST   7
// WebDAV (RFC 4918, RFC 3253 REPORT, RFC 5323 SEARCH) -- needed so a reverse proxy
// can forward Nextcloud/ownCloud/CalDAV/CardDAV traffic with its original method.
#define PROPFINDREQUEST  8
#define PROPPATCHREQUEST 9
#define MKCOLREQUEST     10
#define COPYREQUEST      11
#define MOVEREQUEST      12
#define LOCKREQUEST      13
#define UNLOCKREQUEST    14
#define REPORTREQUEST    15
#define SEARCHREQUEST    16

//define http version