]> git.tdb.fi Git - libs/net.git/blobdiff - source/message.cpp
Add functions for parsing and building URIs and query strings
[libs/net.git] / source / message.cpp
index a8851fa31c4b5b86f9b7df6ff2c0ec60d457ba04..4aaa8bfd26d1fab34302cd6f32e0c583bac133fe 100644 (file)
@@ -12,45 +12,59 @@ Distributed under the LGPL
 
 using namespace std;
 
-#include <iostream>
-
 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[tolower(hdr)]=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
 {
-       HeaderMap::const_iterator i=headers.find(hdr);
+       HeaderMap::const_iterator i=headers.find(normalize_header_name(hdr));
        if(i==headers.end())
-               throw KeyError(format("Header %s is not defined", hdr));
+               throw KeyError("Undefined header", hdr);
 
        return i->second;
 }
 
-void Message::add_data(const string &d)
+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)
 {
-       data+=d;
-       if(headers.count("content-type")==0)
-               set_header("content-type", "text/plain");
-       set_header("content-length", lexical_cast(data.size()));
+       user_data=d;
 }
 
-unsigned Message::parse_data(const string &d)
+unsigned Message::parse_content(const string &d)
 {
        if(complete)
                return 0;
 
-       HeaderMap::const_iterator i=headers.find("content-length");
+       HeaderMap::const_iterator i=headers.find("Content-Length");
        if(i!=headers.end())
        {
-               unsigned needed=lexical_cast<unsigned>(i->second)-data.size();
+               unsigned needed=lexical_cast<unsigned>(i->second)-content.size();
                unsigned len=min(needed, d.size());
                
-               data.append(d, 0, len);
+               content.append(d, 0, len);
 
                if(len==needed)
                        complete=true;
@@ -58,7 +72,7 @@ unsigned Message::parse_data(const string &d)
                return len;
        }
 
-       i=headers.find("transfer-encoding");
+       i=headers.find("Transfer-Encoding");
        if(i!=headers.end() && strcasecmp(i->second, "chunked")==0)
        {
                unsigned pos=0;
@@ -69,8 +83,7 @@ unsigned Message::parse_data(const string &d)
                                unsigned lf=d.find('\n', pos);
                                if(lf==string::npos)
                                        return pos;
-                               // XXX strtoul
-                               chunk_length=strtoul(strip(d.substr(pos, lf-pos)).c_str(), 0, 16);
+                               chunk_length=lexical_cast<unsigned>(strip(d.substr(pos, lf-pos)), "x");
                                if(chunk_length==0)
                                        complete=true;
                                pos=lf+1;
@@ -78,7 +91,7 @@ unsigned Message::parse_data(const string &d)
                        else
                        {
                                unsigned len=min(chunk_length, d.size()-pos);
-                               data.append(d, pos, len);
+                               content.append(d, pos, len);
                                chunk_length-=len;
                                if((pos=d.find('\n', pos+len))!=string::npos)
                                        ++pos;
@@ -88,26 +101,62 @@ unsigned Message::parse_data(const string &d)
                return pos;
        }
 
+       complete=true;
        return 0;
 }
 
-Message::Message():
-       http_version(0x11),
-       chunk_length(0),
-       complete(false)
-{ }
+unsigned Message::parse_headers(const string &d)
+{
+       unsigned start=0;
+       while(1)
+       {
+               unsigned lf=d.find('\n', start);
+               if(lf==string::npos)
+                       throw InvalidParameterValue("Incomplete response");
+               if(lf==start || (d[start]=='\r' && lf==start+1))
+                       return lf+1;
+
+               unsigned colon=d.find(':', start);
+               if(colon>lf)
+                       throw InvalidParameterValue("No colon in header");
+
+               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)
-               result+=format("%s: %s\r\n", i->first, i->second);
+               if(i->first[0]!='-')
+                       result+=format("%s: %s\r\n", i->first, i->second);
        result+="\r\n";
-       result+=data;
+       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