]> git.tdb.fi Git - libs/net.git/blob - source/message.cpp
Add Server class
[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 const string &Message::get_header(const string &hdr) const
30 {
31         HeaderMap::const_iterator i=headers.find(normalize_header_name(hdr));
32         if(i==headers.end())
33                 throw KeyError("Undefined header", hdr);
34
35         return i->second;
36 }
37
38 void Message::add_content(const string &d)
39 {
40         content+=d;
41         if(headers.count("Content-Type")==0)
42                 set_header("Content-Type", "text/plain");
43         set_header("Content-Length", lexical_cast(content.size()));
44 }
45
46 void Message::set_user_data(const Variant &d)
47 {
48         user_data=d;
49 }
50
51 unsigned Message::parse_content(const string &d)
52 {
53         if(complete)
54                 return 0;
55
56         HeaderMap::const_iterator i=headers.find("Content-Length");
57         if(i!=headers.end())
58         {
59                 unsigned needed=lexical_cast<unsigned>(i->second)-content.size();
60                 unsigned len=min(needed, d.size());
61                 
62                 content.append(d, 0, len);
63
64                 if(len==needed)
65                         complete=true;
66                 
67                 return len;
68         }
69
70         i=headers.find("Transfer-Encoding");
71         if(i!=headers.end() && strcasecmp(i->second, "chunked")==0)
72         {
73                 unsigned pos=0;
74                 while(!complete && pos<d.size())
75                 {
76                         if(chunk_length==0)
77                         {
78                                 unsigned lf=d.find('\n', pos);
79                                 if(lf==string::npos)
80                                         return pos;
81                                 chunk_length=lexical_cast<unsigned>(strip(d.substr(pos, lf-pos)), "x");
82                                 if(chunk_length==0)
83                                         complete=true;
84                                 pos=lf+1;
85                         }
86                         else
87                         {
88                                 unsigned len=min(chunk_length, d.size()-pos);
89                                 content.append(d, pos, len);
90                                 chunk_length-=len;
91                                 if((pos=d.find('\n', pos+len))!=string::npos)
92                                         ++pos;
93                         }
94                 }
95
96                 return pos;
97         }
98
99         complete=true;
100         return 0;
101 }
102
103 unsigned Message::parse_headers(const string &d)
104 {
105         unsigned start=0;
106         while(1)
107         {
108                 unsigned lf=d.find('\n', start);
109                 if(lf==string::npos)
110                         throw InvalidParameterValue("Incomplete response");
111                 if(lf==start || (d[start]=='\r' && lf==start+1))
112                         return lf+1;
113
114                 unsigned colon=d.find(':', start);
115                 if(colon>lf)
116                         throw InvalidParameterValue("No colon in header");
117
118                 set_header(d.substr(start, colon-start), strip(d.substr(colon+1, lf-colon-1)));
119
120                 start=lf+1;
121         }
122 }
123
124 string Message::str_common() const
125 {
126         string result;
127
128         for(HeaderMap::const_iterator i=headers.begin(); i!=headers.end(); ++i)
129                 if(i->first[0]!='-')
130                         result+=format("%s: %s\r\n", i->first, i->second);
131         result+="\r\n";
132         result+=content;
133
134         return result;
135 }
136
137 string Message::normalize_header_name(const string &hdr) const
138 {
139         string result=hdr;
140         bool upper=true;
141         for(string::iterator i=result.begin(); i!=result.end(); ++i)
142         {
143                 if(upper)
144                 {
145                         *i=toupper(*i);
146                         upper=false;
147                 }
148                 else if(*i=='-')
149                         upper=true;
150                 else
151                         *i=tolower(*i);
152         }
153         return result;
154 }
155
156 } // namespace Http
157 } // namespace Msp