Loading examples/httpcookie.cpp +6 −10 Original line number Diff line number Diff line Loading @@ -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; Loading examples/httpform.cpp +11 −20 Original line number Diff line number Diff line Loading @@ -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>"; } Loading @@ -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/>"; } }; Loading src/http.cpp +145 −414 File changed.Preview size limit exceeded, changes collapsed. Show changes src/http.h +39 −132 Original line number Diff line number Diff line Loading @@ -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 { Loading src/httpd.cpp +18 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading
examples/httpcookie.cpp +6 −10 Original line number Diff line number Diff line Loading @@ -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; Loading
examples/httpform.cpp +11 −20 Original line number Diff line number Diff line Loading @@ -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>"; } Loading @@ -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/>"; } }; Loading
src/http.h +39 −132 Original line number Diff line number Diff line Loading @@ -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 { Loading
src/httpd.cpp +18 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading