]> git.tdb.fi Git - libs/net.git/blobdiff - source/message.cpp
Pass an exception to signal_socket_error instead of error code
[libs/net.git] / source / message.cpp
index e0a5e7e171bf8afad01cf8932e4ca01acfb720b1..f1e4c286bd13031c1918d21cebacec189200223c 100644 (file)
@@ -1,10 +1,3 @@
-/* $Id$
-
-This file is part of libmsphttp
-Copyright © 2008  Mikkosoft Productions, Mikko Rasa
-Distributed under the LGPL
-*/
-
 #include <cstdlib>
 #include <msp/strings/formatter.h>
 #include <msp/strings/utils.h>
@@ -12,36 +5,45 @@ 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_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()));
+       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;
+       user_data = d;
 }
 
 unsigned Message::parse_content(const string &d)
@@ -49,42 +51,42 @@ 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)-content.size();
-               unsigned len=min(needed, d.size());
+               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;
+                       complete = true;
                
                return len;
        }
 
-       i=headers.find("transfer-encoding");
+       i = headers.find("Transfer-Encoding");
        if(i!=headers.end() && strcasecmp(i->second, "chunked")==0)
        {
-               unsigned pos=0;
+               unsigned pos = 0;
                while(!complete && pos<d.size())
                {
                        if(chunk_length==0)
                        {
-                               unsigned lf=d.find('\n', pos);
+                               unsigned lf = d.find('\n', pos);
                                if(lf==string::npos)
                                        return pos;
-                               chunk_length=lexical_cast<unsigned>(strip(d.substr(pos, lf-pos)), "x");
+                               chunk_length = lexical_cast<unsigned>(strip(d.substr(pos, lf-pos)), "x");
                                if(chunk_length==0)
-                                       complete=true;
-                               pos=lf+1;
+                                       complete = true;
+                               pos = lf+1;
                        }
                        else
                        {
-                               unsigned len=min(chunk_length, d.size()-pos);
+                               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)
+                               chunk_length -= len;
+                               if((pos = d.find('\n', pos+len))!=string::npos)
                                        ++pos;
                        }
                }
@@ -92,26 +94,62 @@ unsigned Message::parse_content(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);
-       result+="\r\n";
-       result+=content;
+               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