]> git.mxchange.org Git - simgear.git/blob - simgear/io/HTTPRequest.cxx
HTTP enhancements.
[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         return ""; // couldn't parse host
117     }
118     
119     int query = u.find('?', hostEnd + 1);
120     if (query < 0) {
121         // all remainder of URL is path
122         return u.substr(hostEnd);
123     }
124     
125     return u.substr(hostEnd, query - hostEnd);
126 }
127
128
129 string Request::query() const
130 {
131   string u(url());
132   int query = u.find('?');
133   if (query < 0) {
134     return "";  //no query string found
135   }
136   
137   return u.substr(query);   //includes question mark
138 }
139
140
141
142 string Request::host() const
143 {
144     string hp(hostAndPort());
145     int colonPos = hp.find(':');
146     if (colonPos >= 0) {
147         return hp.substr(0, colonPos); // trim off the colon and port
148     } else {
149         return hp; // no port specifier
150     }
151 }
152
153 unsigned short Request::port() const
154 {
155     string hp(hostAndPort());
156     int colonPos = hp.find(':');
157     if (colonPos >= 0) {
158         return (unsigned short) strutils::to_int(hp.substr(colonPos + 1));
159     } else {
160         return DEFAULT_HTTP_PORT;
161     }
162 }
163
164 string Request::hostAndPort() const
165 {
166     string u(url());
167     int schemeEnd = u.find("://");
168     if (schemeEnd < 0) {
169         return ""; // couldn't parse scheme
170     }
171     
172     int hostEnd = u.find('/', schemeEnd + 3);
173     if (hostEnd < 0) { // all remainder of URL is host
174         return u.substr(schemeEnd + 3);
175     }
176     
177     return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3));
178 }
179
180 void Request::setResponseLength(unsigned int l)
181 {
182     _responseLength = l;
183 }
184
185 unsigned int Request::responseLength() const
186 {
187 // if the server didn't supply a content length, use the number
188 // of bytes we actually received (so far)
189     if ((_responseLength == 0) && (_receivedBodyBytes > 0)) {
190         return _receivedBodyBytes;
191     }
192     
193     return _responseLength;
194 }
195
196 void Request::setFailure(int code, const std::string& reason)
197 {
198     _responseStatus = code;
199     _responseReason = reason;
200     failed();
201 }
202
203 void Request::failed()
204 {
205     // no-op in base class
206 }
207
208 Request::HTTPVersion Request::decodeVersion(const string& v)
209 {
210     if (v == "HTTP/1.1") return HTTP_1_1;
211     if (v == "HTTP/1.0") return HTTP_1_0;
212     if (strutils::starts_with(v, "HTTP/0.")) return HTTP_0_x;
213     return HTTP_VERSION_UNKNOWN;
214 }
215
216 bool Request::closeAfterComplete() const
217 {
218 // for non HTTP/1.1 connections, assume server closes
219     return _willClose || (_responseVersion != HTTP_1_1);
220 }
221   
222 int Request::requestBodyLength() const
223 {
224   return -1;
225 }
226
227 std::string Request::requestBodyType() const
228 {
229     return "text/plain";
230 }
231   
232 void Request::getBodyData(char*, int& count) const
233 {
234   count = 0;
235   return;
236 }
237
238 } // of namespace HTTP
239
240 } // of namespace simgear