1 // Sun, 18 Jun 2000
2 // Y.Takagi
3
4 #include <list>
5 #include <algorithm>
6 #include <cstring>
7 #include <strings.h>
8
9 #define stricmp strcasecmp
10
11 #include "HttpURLConnection.h"
12 #include "Socket.h"
13
14 using namespace std;
15
16 #define DEFAULT_PORT 80;
17
Field(char * field)18 Field::Field(char *field)
19 {
20 char *p = strtok(field, ": \t\r\n");
21 key = p ? p : "";
22 p = strtok(NULL, " \t\r\n");
23 value = p ? p : "";
24 }
25
Field(const char * k,const char * v)26 Field::Field(const char *k, const char *v)
27 {
28 key = k ? k : "";
29 value = v ? v : "";
30 }
31
Field(const Field & o)32 Field::Field(const Field &o)
33 {
34 key = o.key;
35 value = o.value;
36 }
37
operator =(const Field & o)38 Field &Field::operator = (const Field &o)
39 {
40 key = o.key;
41 value = o.value;
42 return *this;
43 }
44
operator ==(const Field & o)45 bool Field::operator == (const Field &o)
46 {
47 return (key == o.key) && (value == o.value);
48 }
49
HttpURLConnection(const BUrl & Url)50 HttpURLConnection::HttpURLConnection(const BUrl &Url)
51 : connected(false), doInput(true), doOutput(false), url(Url)
52 {
53 __sock = NULL;
54 __method = "GET";
55 __request = NULL;
56 __response = NULL;
57 __response_code = HTTP_UNKNOWN;
58 }
59
~HttpURLConnection()60 HttpURLConnection::~HttpURLConnection()
61 {
62 disconnect();
63
64 if (__sock) {
65 delete __sock;
66 }
67
68 if (__request) {
69 delete __request;
70 }
71
72 if (__response) {
73 delete __response;
74 }
75 }
76
disconnect()77 void HttpURLConnection::disconnect()
78 {
79 if (connected) {
80 connected = false;
81 __sock->close();
82 }
83 }
84
getRequestMethod() const85 const char *HttpURLConnection::getRequestMethod() const
86 {
87 return __method.c_str();
88 }
89
setRequestMethod(const char * method)90 void HttpURLConnection::setRequestMethod(const char *method)
91 {
92 __method = method;
93 }
94
setRequestProperty(const char * key,const char * value)95 void HttpURLConnection::setRequestProperty(const char *key, const char *value)
96 {
97 if (__request == NULL) {
98 __request = new Fields;
99 }
100 __request->push_back(Field(key, value));
101 }
102
getInputStream()103 istream &HttpURLConnection::getInputStream()
104 {
105 if (!connected) {
106 connect();
107 setRequest();
108 }
109 return __sock->getInputStream();
110 }
111
getOutputStream()112 ostream &HttpURLConnection::getOutputStream()
113 {
114 if (!connected) {
115 connect();
116 }
117 return __sock->getOutputStream();
118 }
119
setDoInput(bool doInput)120 void HttpURLConnection::setDoInput(bool doInput)
121 {
122 this->doInput = doInput;
123 }
124
setDoOutput(bool doOutput)125 void HttpURLConnection::setDoOutput(bool doOutput)
126 {
127 this->doOutput = doOutput;
128 }
129
connect()130 void HttpURLConnection::connect()
131 {
132 if (!connected) {
133 int port = url.Port();
134 if (port < 0) {
135 const char *protocol = url.Protocol();
136 if (!stricmp(protocol, "http")) {
137 port = DEFAULT_PORT;
138 } else if (!stricmp(protocol, "ipp")) {
139 port = 631;
140 } else {
141 port = DEFAULT_PORT;
142 }
143 }
144 __sock = new Socket(url.Host(), port);
145 if (__sock->fail()) {
146 __error_msg = __sock->getLastError();
147 } else {
148 connected = true;
149 }
150 }
151 }
152
getContentType()153 const char *HttpURLConnection::getContentType()
154 {
155 return getHeaderField("Content-Type");
156 }
157
getContentEncoding()158 const char *HttpURLConnection::getContentEncoding()
159 {
160 return getHeaderField("Content-Encoding");
161 }
162
getContentLength()163 int HttpURLConnection::getContentLength()
164 {
165 const char *p = getHeaderField("Content-Length");
166 return p ? atoi(p) : -1;
167 }
168
getHeaderField(const char * s)169 const char *HttpURLConnection::getHeaderField(const char *s)
170 {
171 if (__response == NULL) {
172 action();
173 }
174 if (__response) {
175 for (Fields::iterator it = __response->begin(); it != __response->end(); it++) {
176 if ((*it).key == s) {
177 return (*it).value.c_str();
178 }
179 }
180 }
181 return NULL;
182 }
183
getResponseCode()184 HTTP_RESPONSECODE HttpURLConnection::getResponseCode()
185 {
186 if (__response == NULL) {
187 action();
188 }
189 return __response_code;
190 }
191
getResponseMessage()192 const char *HttpURLConnection::getResponseMessage()
193 {
194 if (__response == NULL) {
195 action();
196 }
197 return __response_message.c_str();
198 }
199
action()200 void HttpURLConnection::action()
201 {
202 if (!connected) {
203 connect();
204 }
205 if (connected) {
206 setRequest();
207 }
208 if (connected) {
209 getResponse();
210 }
211 }
212
setRequest()213 void HttpURLConnection::setRequest()
214 {
215 if (connected) {
216 setRequestProperty("Host", url.Host());
217 ostream &os = getOutputStream();
218 os << __method << ' ' << url.Path() << " HTTP/1.1" << '\r' << '\n';
219 for (Fields::iterator it = __request->begin(); it != __request->end(); it++) {
220 os << (*it).key << ": " << (*it).value << '\r' << '\n';
221 }
222 os << '\r' << '\n';
223
224 setContent();
225
226 if (!doOutput) {
227 os.flush();
228 }
229
230 if (__response) {
231 delete __response;
232 __response = NULL;
233 }
234 }
235 }
236
setContent()237 void HttpURLConnection::setContent()
238 {
239 }
240
getResponse()241 void HttpURLConnection::getResponse()
242 {
243 if (connected) {
244
245 if (__response == NULL) {
246 __response = new Fields;
247
248 istream &is = getInputStream();
249
250 char buffer[1024];
251
252 if (!is.getline(buffer, sizeof(buffer))) {
253 __error_msg = __sock->getLastError();
254 return;
255 }
256 buffer[is.gcount() - 2] = '\0';
257 __response_message = buffer;
258 strtok(buffer, " ");
259 char *p = strtok(NULL, " ");
260 __response_code = p ? (HTTP_RESPONSECODE)atoi(p) : HTTP_UNKNOWN;
261
262 while (is.getline(buffer, sizeof(buffer))) {
263 if (buffer[0] == '\r') {
264 break;
265 }
266 buffer[is.gcount() - 2] = '\0';
267 __response->push_back(Field(buffer));
268 }
269
270 int size = getContentLength();
271 if (size > 0) {
272 getContent();
273 }
274
275 if (__response_code != HTTP_CONTINUE) {
276 const char *s = getHeaderField("Connection");
277 if (s == NULL) {
278 connected = false;
279 __error_msg = "cannot found \"Connection\" field";
280 } else if (stricmp(s, "Keep-Alive")) {
281 connected = false;
282 }
283 }
284
285 switch (__response_code) {
286 case HTTP_MOVED_TEMP:
287 {
288 const char *p = getHeaderField("Location");
289 if (p) {
290 BUrl trueUrl(p);
291 url = trueUrl;
292 delete __response;
293 __response = NULL;
294 action();
295 }
296 }
297 break;
298 case HTTP_CONTINUE:
299 delete __response;
300 __response = NULL;
301 getResponse();
302 break;
303 default:
304 break;
305 }
306 }
307 }
308 }
309
getContent()310 void HttpURLConnection::getContent()
311 {
312 const int maxBufSize = 1024;
313 if (connected) {
314 int size = getContentLength();
315 if (size > 0) {
316 istream &is = getInputStream();
317 int bufsize = min(size, maxBufSize);
318 char buf[maxBufSize];
319 while (size > 0 && is.read(buf, bufsize)) {
320 size -= bufsize;
321 }
322 }
323 }
324 }
325