]> git.tdb.fi Git - libs/net.git/blob - source/message.cpp
Style update: spaces around assignments
[libs/net.git] / source / message.cpp
1 /* $Id$
2
3 This file is part of libmsphttp
4 Copyright © 2008  Mikkosoft Productions, Mikko Rasa
5 Distributed under the LGPL
6 */
7
8 #include <cstdlib>
9 #include <msp/strings/formatter.h>
10 #include <msp/strings/utils.h>
11 #include "message.h"
12
13 using namespace std;
14
15 namespace Msp {
16 namespace Http {
17
18 Message::Message():
19         http_version(0x11),
20         chunk_length(0),
21         complete(false)
22 { }
23
24 void Message::set_header(const string &hdr, const string &val)
25 {
26         headers[normalize_header_name(hdr)] = val;
27 }
28
29 bool Message::has_header(const string &hdr) const
30 {
31         return headers.count(normalize_header_name(hdr));
32 }
33
34 const string &Message::get_header(const string &hdr) const
35 {
36         HeaderMap::const_iterator i = headers.find(normalize_header_name(hdr));
37         if(i==headers.end())
38                 throw KeyError("Undefined header", hdr);
39
40         return i->second;
41 }
42
43 void Message::add_content(const string &d)
44 {
45         content += d;
46         if(headers.count("Content-Type")==0)
47                 set_header("Content-Type", "text/plain");
48         set_header("Content-Length", lexical_cast(content.size()));
49 }
50
51 void Message::set_user_data(const Variant &d)
52 {
53         user_data = d;
54 }
55
56 unsigned Message::parse_content(const string &d)
57 {
58         if(complete)
59                 return 0;
60
61         HeaderMap::const_iterator i = headers.find("Content-Length");
62         if(i!=headers.end())
63         {
64                 unsigned needed = lexical_cast<unsigned>(i->second)-content.size();
65                 unsigned len = min(needed, d.size());
66                 
67                 content.append(d, 0, len);
68
69                 if(len==needed)
70                         complete = true;
71                 
72                 return len;
73         }
74
75         i = headers.find("Transfer-Encoding");
76         if(i!=headers.end() && strcasecmp(i->second, "chunked")==0)
77         {
78                 unsigned pos = 0;
79                 while(!complete && pos<d.size())
80                 {
81                         if(chunk_length==0)
82                         {
83                                 unsigned lf = d.find('\n', pos);
84                                 if(lf==string::npos)
85                                         return pos;
86                                 chunk_length = lexical_cast<unsigned>(strip(d.substr(pos, lf-pos)), "x");
87                                 if(chunk_length==0)
88                                         complete = true;
89                                 pos = lf+1;
90                         }
91                         else
92                         {
93                                 unsigned len = min(chunk_length, d.size()-pos);
94                                 content.append(d, pos, len);
95                                 chunk_length -= len;
96                                 if((pos = d.find('\n', pos+len))!=string::npos)
97                                         ++pos;
98                         }
99                 }
100
101                 return pos;
102         }
103
104         complete = true;
105         return 0;
106 }
107
108 unsigned Message::parse_headers(const string &d)
109 {
110         unsigned start = 0;
111         while(1)
112         {
113                 unsigned lf = d.find('\n', start);
114                 if(lf==string::npos)
115                         throw InvalidParameterValue("Incomplete response");
116                 if(lf==start || (d[start]=='\r' && lf==start+1))
117                         return lf+1;
118
119                 unsigned colon = d.find(':', start);
120                 if(colon>lf)
121                         throw InvalidParameterValue("No colon in header");
122
123                 set_header(d.substr(start, colon-start), strip(d.substr(colon+1, lf-colon-1)));
124
125                 start = lf+1;
126         }
127 }
128
129 string Message::str_common() const
130 {
131         string result;
132
133         for(HeaderMap::const_iterator i=headers.begin(); i!=headers.end(); ++i)
134                 if(i->first[0]!='-')
135                         result += format("%s: %s\r\n", i->first, i->second);
136         result += "\r\n";
137         result += content;
138
139         return result;
140 }
141
142 string Message::normalize_header_name(const string &hdr) const
143 {
144         string result = hdr;
145         bool upper = true;
146         for(string::iterator i=result.begin(); i!=result.end(); ++i)
147         {
148                 if(upper)
149                 {
150                         *i = toupper(*i);
151                         upper = false;
152                 }
153                 else if(*i=='-')
154                         upper = true;
155                 else
156                         *i = tolower(*i);
157         }
158         return result;
159 }
160
161 } // namespace Http
162 } // namespace Msp