]> git.mxchange.org Git - simgear.git/blob - simgear/io/HTTPRequest.cxx
Ensure individual log-level setting works.
[simgear.git] / simgear / io / HTTPRequest.cxx
1 #include "HTTPRequest.hxx"
2
3 #include <simgear/misc/strutils.hxx>
4 #include <simgear/compiler.h>
5 #include <simgear/debug/logstream.hxx>
6
7 using std::string;
8 using std::map;
9
10 namespace simgear
11 {
12
13 namespace HTTP
14 {
15
16 extern const int DEFAULT_HTTP_PORT;
17
18 Request::Request(const string& url, const string method) :
19     _method(method),
20     _url(url),
21     _responseVersion(HTTP_VERSION_UNKNOWN),
22     _responseStatus(0),
23     _responseLength(0),
24     _receivedBodyBytes(0),
25     _willClose(false)
26 {
27     
28 }
29
30 Request::~Request()
31 {
32     
33 }
34
35 void Request::setUrl(const string& url)
36 {
37     _url = url;
38 }
39
40 string_list Request::requestHeaders() const
41 {
42     string_list r;
43     return r;
44 }
45
46 string Request::header(const std::string& name) const
47 {
48     return string();
49 }
50
51 void Request::responseStart(const string& r)
52 {
53     const int maxSplit = 2; // HTTP/1.1 nnn reason-string
54     string_list parts = strutils::split(r, NULL, maxSplit);
55     if (parts.size() != 3) {
56         SG_LOG(SG_IO, SG_WARN, "HTTP::Request: malformed response start:" << r);
57         setFailure(400, "malformed HTTP response header");
58         return;
59     }
60     
61     _responseVersion = decodeVersion(parts[0]);    
62     _responseStatus = strutils::to_int(parts[1]);
63     _responseReason = parts[2];
64 }
65
66 void Request::responseHeader(const string& key, const string& value)
67 {
68     if (key == "connection") {
69         _willClose = (value.find("close") != string::npos);
70     }
71     
72     _responseHeaders[key] = value;
73 }
74
75 void Request::responseHeadersComplete()
76 {
77     // no op
78 }
79
80 void Request::processBodyBytes(const char* s, int n)
81 {
82     _receivedBodyBytes += n;
83     gotBodyData(s, n);
84 }
85
86 void Request::gotBodyData(const char* s, int n)
87 {
88
89 }
90
91 void Request::responseComplete()
92 {
93     
94 }
95     
96 string Request::scheme() const
97 {
98     int firstColon = url().find(":");
99     if (firstColon > 0) {
100         return url().substr(0, firstColon);
101     }
102     
103     return ""; // couldn't parse scheme
104 }
105     
106 string Request::path() const
107 {
108     string u(url());
109     int schemeEnd = u.find("://");
110     if (schemeEnd < 0) {
111         return ""; // couldn't parse scheme
112     }
113     
114     int hostEnd = u.find('/', schemeEnd + 3);
115     if (hostEnd < 0) {
116 // couldn't parse host, or URL looks like 'http://foo.com' (no trailing '/') 
117 // fixup to root resource path: '/' 
118         return "/"; 
119     }
120     
121     int query = u.find('?', hostEnd + 1);
122     if (query < 0) {
123         // all remainder of URL is path
124         return u.substr(hostEnd);
125     }
126     
127     return u.substr(hostEnd, query - hostEnd);
128 }
129
130
131 string Request::query() const
132 {
133   string u(url());
134   int query = u.find('?');
135   if (query < 0) {
136     return "";  //no query string found
137   }
138   
139   return u.substr(query);   //includes question mark
140 }
141
142
143
144 string Request::host() const
145 {
146     string hp(hostAndPort());
147     int colonPos = hp.find(':');
148     if (colonPos >= 0) {
149         return hp.substr(0, colonPos); // trim off the colon and port
150     } else {
151         return hp; // no port specifier
152     }
153 }
154
155 unsigned short Request::port() const
156 {
157     string hp(hostAndPort());
158     int colonPos = hp.find(':');
159     if (colonPos >= 0) {
160         return (unsigned short) strutils::to_int(hp.substr(colonPos + 1));
161     } else {
162         return DEFAULT_HTTP_PORT;
163     }
164 }
165
166 string Request::hostAndPort() const
167 {
168     string u(url());
169     int schemeEnd = u.find("://");
170     if (schemeEnd < 0) {
171         return ""; // couldn't parse scheme
172     }
173     
174     int hostEnd = u.find('/', schemeEnd + 3);
175     if (hostEnd < 0) { // all remainder of URL is host
176         return u.substr(schemeEnd + 3);
177     }
178     
179     return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3));
180 }
181
182 void Request::setResponseLength(unsigned int l)
183 {
184     _responseLength = l;
185 }
186
187 unsigned int Request::responseLength() const
188 {
189 // if the server didn't supply a content length, use the number
190 // of bytes we actually received (so far)
191     if ((_responseLength == 0) && (_receivedBodyBytes > 0)) {
192         return _receivedBodyBytes;
193     }
194     
195     return _responseLength;
196 }
197
198 void Request::setFailure(int code, const std::string& reason)
199 {
200     _responseStatus = code;
201     _responseReason = reason;
202     failed();
203 }
204
205 void Request::failed()
206 {
207     // no-op in base class
208     SG_LOG(SG_IO, SG_INFO, "request failed:" << url());
209 }
210
211 Request::HTTPVersion Request::decodeVersion(const string& v)
212 {
213     if (v == "HTTP/1.1") return HTTP_1_1;
214     if (v == "HTTP/1.0") return HTTP_1_0;
215     if (strutils::starts_with(v, "HTTP/0.")) return HTTP_0_x;
216     return HTTP_VERSION_UNKNOWN;
217 }
218
219 bool Request::closeAfterComplete() const
220 {
221 // for non HTTP/1.1 connections, assume server closes
222     return _willClose || (_responseVersion != HTTP_1_1);
223 }
224   
225 int Request::requestBodyLength() const
226 {
227   return -1;
228 }
229
230 std::string Request::requestBodyType() const
231 {
232     return "text/plain";
233 }
234   
235 void Request::getBodyData(char*, int& count) const
236 {
237   count = 0;
238   return;
239 }
240
241 } // of namespace HTTP
242
243 } // of namespace simgear