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