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