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