xref: /haiku/src/add-ons/print/transports/ipp/HttpURLConnection.cpp (revision 33984e7b7da49e778f7265b5fca0b2cc4b4f6f88)
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