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

new http form api

parent 3d158435
Loading
Loading
Loading
Loading
+6 −10
Original line number Diff line number Diff line
@@ -68,21 +68,17 @@ public:
    };
    
    const std::string &getData(const std::string &key,libhttppp::HttpForm &curform){
        for(libhttppp::HttpForm::UrlcodedForm::Data *cururlform=curform.UrlFormData.getFormData() ; cururlform;
            cururlform=cururlform->nextData()){
            if(cururlform->getKey()==key)
                return cururlform->getValue();
        for(const auto &entry : curform.urlData()){
            if(entry.key==key)
                return entry.value;
        }
        return emtpystring;
    }
    
    int getDataInt(const std::string &key,libhttppp::HttpForm &curform){
        for(libhttppp::HttpForm::UrlcodedForm::Data *cururlform=curform.UrlFormData.getFormData(); cururlform;
            cururlform=cururlform->nextData()){
            if(key==cururlform->getKey()){
                    char ktmp[255];
                    memcpy(ktmp,cururlform->getValue().c_str(),cururlform->getValue().length());
                    return atoi(ktmp);
        for(const auto &entry : curform.urlData()){
            if(key==entry.key){
                    return std::atoi(entry.value.c_str());
                }
        }
        return 0;
+11 −20
Original line number Diff line number Diff line
@@ -68,25 +68,17 @@ private:
        libhttppp::HttpForm curform;
        curform.parse(curreq);

        if (curform.getBoundary()) {
            condat << "Boundary: " << curform.getBoundary() << "<br>";
            for (libhttppp::HttpForm::MultipartForm::Data* curformdat = curform.MultipartFormData.getFormData();
                 curformdat; curformdat = curformdat->nextData()) {
        if (!curform.getBoundary().empty()) {
            condat << "Boundary: " << curform.getBoundary().c_str() << "<br>";
            for (const auto &entry : curform.multipartData()) {
                condat << "Content-Disposition: <br>";
                for(libhttppp::HttpForm::MultipartForm::Data::ContentDisposition *curdispo=curformdat->getDisposition();
                    curdispo; curdispo=curdispo->nextContentDisposition()
                ){
                        condat << "Key: ";
                        if(!curdispo->getKey().empty())
                             condat  << curdispo->getKey().data()
                        << " Value: ";
                        if(!curdispo->getValue().empty())
                             condat << curdispo->getValue().data()
                        << " ";
                for (const auto &dispo : entry.dispositions) {
                    condat << "Key: " << dispo.key.c_str()
                           << " Value: " << dispo.value.c_str() << " ";
                }
                condat << "<br>";
                if (!curformdat->Value.empty()){
                    std::copy(curformdat->Value.begin(), curformdat->Value.end(), std::back_inserter(condat));
                if (!entry.value.empty()) {
                    std::copy(entry.value.begin(), entry.value.end(), std::back_inserter(condat));
                }
                condat << "<br>";
            }
@@ -98,11 +90,10 @@ private:
        libhttppp::HttpForm curform;
        curform.parse(curreq);

        for (libhttppp::HttpForm::UrlcodedForm::Data* cururlform = curform.UrlFormData.getFormData(); cururlform;
             cururlform = cururlform->nextData()) {
        for (const auto &entry : curform.urlData()) {
            condat << "<span>"
                   << "Key: " << cururlform->getKey()
                   << " Value: " << cururlform->getValue()
                   << "Key: " << entry.key.c_str()
                   << " Value: " << entry.value.c_str()
                   << "</span><br/>";
        }
    };
+145 −414

File changed.

Preview size limit exceeded, changes collapsed.

+39 −132
Original line number Diff line number Diff line
@@ -327,146 +327,53 @@ namespace libhttppp {
  
  class HttpForm {
  public:
    class MultipartForm{
    public:
      class Data{
        public:
        class Content {
        public:
          const std::vector<char> &getKey() const;
          const std::vector<char> &getValue() const;

          void setKey(const std::vector<char> &key);
          void setValue(const std::vector<char> &value);

          Content()=default;
          ~Content()=default;
          Content(const Content &src);

          Content *nextContent();

        private:
          std::unique_ptr<Content> _nextContent=nullptr;
          std::vector<char>   _Key;
          std::vector<char>   _Value;
          friend class HttpForm;
          friend class MultipartFormData;
    // ─── Multipart form-data (RFC 2046) ───────────────────
    struct MultipartEntry {
      struct Header {
        std::string key;    // lowercased header name (e.g. "content-disposition")
        std::string value;  // full header value
      };

        class ContentDisposition{
        public:
          const std::vector<char> &getKey() const;
          const std::vector<char> &getValue() const;

          void setKey(const std::vector<char> &key);
          void setValue(const std::vector<char> &value);

          ContentDisposition()=default;
          ~ContentDisposition()=default;
          ContentDisposition(const ContentDisposition &src);

          ContentDisposition *nextContentDisposition() const;

        private:
          std::unique_ptr <ContentDisposition> _nextContentDisposition=nullptr;
          std::vector<char>   _Key;
          std::vector<char>   _Value;
          friend class HttpForm;
          friend class MultipartFormData;
      struct Disposition {
        std::string key;    // e.g. "name", "filename"
        std::string value;  // e.g. "field1", "upload.txt"
      };

        ContentDisposition *getDisposition();
        void                addDisposition(ContentDisposition disposition);

        const Content   *getContent() const;
        void                    addContent(const Content& content);

        std::vector<char>   Value;
        Data               *nextData();
        Data() = default;
        ~Data() = default;
        Data(Data &src);
      private:

        std::unique_ptr <Content> _firstContent=nullptr;
        Content*                              _lastContent=nullptr;

        std::unique_ptr <ContentDisposition> _firstDisposition=nullptr;
        ContentDisposition                              *_lastDisposition=nullptr;
        std::unique_ptr <Data>       _nextData=nullptr;
        friend class HttpForm;
        friend class MultipartFormData;
      std::vector<Header>      headers;
      std::vector<Disposition> dispositions;
      std::vector<char>        value;  // raw body (binary-safe for file uploads)
    };

      Data               *getFormData();

      MultipartForm()=default;
      ~MultipartForm()=default;
    private:
      std::unique_ptr <Data> _firstData=nullptr;
      Data                              *_lastData=nullptr;

      void                _parseContentDisposition(const char *disposition);

      friend class HttpForm;
    // ─── URL-encoded form data ────────────────────────────
    struct UrlEntry {
      std::string key;
      std::string value;
    };

    class UrlcodedForm{
    public:
      class Data {
        public:
          Data(const Data &fdat);
          Data(const char *key,const char *value);
          Data()=default;
          ~Data()=default;
          const std::string &getKey();
          const std::string &getValue();
      
          void          setKey(const std::string &key);
          void          setValue(const std::string &value);
          Data         *nextData();
        private:
          std::string        _Key;
          std::string        _Value;
          std::unique_ptr <Data> _next;
          friend class HttpForm;
      };
    HttpForm() = default;
    ~HttpForm() = default;

      UrlcodedForm()=default;
      ~UrlcodedForm()=default;
    void parse(HttpRequest &request);

      void  addFormData(Data &formdat);
      Data *getFormData();
    private:
      std::unique_ptr <Data> _firstData;
      Data *_lastData;
      friend class HttpForm;
    };
    // Accessors
    const std::string                  &getContentType() const { return _contentType; }
    const std::string                  &getBoundary()    const { return _boundary; }
    const std::vector<MultipartEntry>  &multipartData()  const { return _multipartEntries; }
    const std::vector<UrlEntry>        &urlData()        const { return _urlEntries; }

    HttpForm();
    ~HttpForm();
    void                parse(libhttppp::HttpRequest &request);
    const char         *getContentType();
    /*urldecoded form*/
    // URL encoding / decoding utilities
    static void urlDecode(const std::string &in, std::string &out);
    static void urlEncode(const std::string &in, std::string &out);
    UrlcodedForm        UrlFormData;
    /*multiform*/
    const char         *getBoundary();
    size_t                  getBoundarySize();
    MultipartForm     MultipartFormData;
  private:
    /*urldecoded*/
    void               _parseUrlDecode(const netplus::condata<char> &data,size_t csize);

    /*multiform*/
    void               _parseMulitpart(const netplus::condata<char> &data);
    void               _parseMultiSection(const netplus::condata<char> &data,size_t start, size_t end);
    std::vector<char>  _Boundary;
    
    /*both methods*/
    size_t             _Elements;
    const char*        _ContentType;
  private:
    void _parseMultipart(const char *data, size_t len);
    void _parseMultiSection(const char *data, size_t len, size_t start, size_t end);
    void _parseUrlDecode(const char *data, size_t len);

    std::string                  _boundary;
    std::string                  _contentType;
    std::vector<MultipartEntry>  _multipartEntries;
    std::vector<UrlEntry>        _urlEntries;
  };

  class HttpCookie {
+18 −4
Original line number Diff line number Diff line
@@ -731,13 +731,20 @@ REQUESTHANDLING:
                RequestEvent(cureq,tid,args);
                cureq._RequestType=PARSEREQUEST;
                break;
            case POSTREQUEST:
                if(cureq.RecvData.size()>=cureq.getContentLength()){
            case POSTREQUEST: {
                size_t clen = cureq.getContentLength();
                if(clen == 0){
                    // No Content-Length or zero-length body: dispatch immediately
                    // without waiting for body data
                    RequestEvent(cureq,tid,args);
                    cureq.RecvData.erase(cureq.RecvData.begin(),cureq.RecvData.begin()+cureq.getContentLength());
                    cureq._RequestType=PARSEREQUEST;
                } else if(cureq.RecvData.size()>=clen){
                    RequestEvent(cureq,tid,args);
                    cureq.RecvData.erase(cureq.RecvData.begin(),cureq.RecvData.begin()+clen);
                    cureq._RequestType=PARSEREQUEST;
                }
                break;
            }
            default:{
                cureq.clear();
                libhttppp::HTTPException re;
@@ -778,7 +785,14 @@ void libhttppp::HttpEvent::ResponseEvent(netplus::con &curcon,const int tid,ULON
            return;
        }

        // Skip spurious calls when there is no active request
        // Skip when there is no active request or when still waiting
        // for POST body data to arrive (clearing state prematurely would
        // 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) {
            return;
        }
        if (cureq.getRequestType() == PARSEREQUEST && cureq.getRequestURL().empty()) {
            return;
        }