]> git.tdb.fi Git - libs/net.git/blobdiff - source/http/message.cpp
Prepare for assimilation into mspnet
[libs/net.git] / source / http / message.cpp
diff --git a/source/http/message.cpp b/source/http/message.cpp
new file mode 100644 (file)
index 0000000..2b3e40b
--- /dev/null
@@ -0,0 +1,152 @@
+#include <cstdlib>
+#include <msp/core/maputils.h>
+#include <msp/strings/formatter.h>
+#include <msp/strings/utils.h>
+#include "message.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Http {
+
+Message::Message():
+       http_version(0x11),
+       chunk_length(0),
+       complete(false)
+{ }
+
+void Message::set_header(const string &hdr, const string &val)
+{
+       headers[normalize_header_name(hdr)] = val;
+}
+
+bool Message::has_header(const string &hdr) const
+{
+       return headers.count(normalize_header_name(hdr));
+}
+
+const string &Message::get_header(const string &hdr) const
+{
+       return get_item(headers, normalize_header_name(hdr));
+}
+
+void Message::add_content(const string &d)
+{
+       content += d;
+       if(headers.count("Content-Type")==0)
+               set_header("Content-Type", "text/plain");
+       set_header("Content-Length", lexical_cast(content.size()));
+}
+
+void Message::set_user_data(const Variant &d)
+{
+       user_data = d;
+}
+
+unsigned Message::parse_content(const string &d)
+{
+       if(complete)
+               return 0;
+
+       HeaderMap::const_iterator i = headers.find("Content-Length");
+       if(i!=headers.end())
+       {
+               unsigned needed = lexical_cast<unsigned>(i->second)-content.size();
+               unsigned len = min(needed, d.size());
+               
+               content.append(d, 0, len);
+
+               if(len==needed)
+                       complete = true;
+               
+               return len;
+       }
+
+       i = headers.find("Transfer-Encoding");
+       if(i!=headers.end() && strcasecmp(i->second, "chunked")==0)
+       {
+               unsigned pos = 0;
+               while(!complete && pos<d.size())
+               {
+                       if(chunk_length==0)
+                       {
+                               unsigned lf = d.find('\n', pos);
+                               if(lf==string::npos)
+                                       return pos;
+                               chunk_length = lexical_cast<unsigned>(strip(d.substr(pos, lf-pos)), "x");
+                               if(chunk_length==0)
+                                       complete = true;
+                               pos = lf+1;
+                       }
+                       else
+                       {
+                               unsigned len = min(chunk_length, d.size()-pos);
+                               content.append(d, pos, len);
+                               chunk_length -= len;
+                               if((pos = d.find('\n', pos+len))!=string::npos)
+                                       ++pos;
+                       }
+               }
+
+               return pos;
+       }
+
+       complete = true;
+       return 0;
+}
+
+unsigned Message::parse_headers(const string &d)
+{
+       unsigned start = 0;
+       while(1)
+       {
+               unsigned lf = d.find('\n', start);
+               if(lf==string::npos)
+                       throw invalid_argument("Message::parse_headers");
+               if(lf==start || (d[start]=='\r' && lf==start+1))
+                       return lf+1;
+
+               unsigned colon = d.find(':', start);
+               if(colon>lf)
+                       throw invalid_argument("Message::parse_headers");
+
+               set_header(d.substr(start, colon-start), strip(d.substr(colon+1, lf-colon-1)));
+
+               start = lf+1;
+       }
+}
+
+string Message::str_common() const
+{
+       string result;
+
+       for(HeaderMap::const_iterator i=headers.begin(); i!=headers.end(); ++i)
+               if(i->first[0]!='-')
+                       result += format("%s: %s\r\n", i->first, i->second);
+       result += "\r\n";
+       result += content;
+
+       return result;
+}
+
+string Message::normalize_header_name(const string &hdr) const
+{
+       string result = hdr;
+       bool upper = true;
+       for(string::iterator i=result.begin(); i!=result.end(); ++i)
+       {
+               if(upper)
+               {
+                       *i = toupper(*i);
+                       upper = false;
+               }
+               else if(*i=='-')
+                       upper = true;
+               else
+                       *i = tolower(*i);
+       }
+       return result;
+}
+
+} // namespace Http
+} // namespace Msp