vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / print / transports / ipp / HttpURLConnection.cpp
blob729ac598bbd0ce2b3f3398670d40a53fd46da312
1 // Sun, 18 Jun 2000
2 // Y.Takagi
4 #include <list>
5 #include <algorithm>
6 #include <cstring>
7 #include <strings.h>
9 #define stricmp strcasecmp
11 #include "HttpURLConnection.h"
12 #include "Socket.h"
14 using namespace std;
16 #define DEFAULT_PORT 80;
18 Field::Field(char *field)
20 char *p = strtok(field, ": \t\r\n");
21 key = p ? p : "";
22 p = strtok(NULL, " \t\r\n");
23 value = p ? p : "";
26 Field::Field(const char *k, const char *v)
28 key = k ? k : "";
29 value = v ? v : "";
32 Field::Field(const Field &o)
34 key = o.key;
35 value = o.value;
38 Field &Field::operator = (const Field &o)
40 key = o.key;
41 value = o.value;
42 return *this;
45 bool Field::operator == (const Field &o)
47 return (key == o.key) && (value == o.value);
50 HttpURLConnection::HttpURLConnection(const URL &Url)
51 : connected(false), doInput(true), doOutput(false), url(Url)
53 __sock = NULL;
54 __method = "GET";
55 __request = NULL;
56 __response = NULL;
57 __response_code = HTTP_UNKNOWN;
60 HttpURLConnection::~HttpURLConnection()
62 disconnect();
64 if (__sock) {
65 delete __sock;
68 if (__request) {
69 delete __request;
72 if (__response) {
73 delete __response;
77 void HttpURLConnection::disconnect()
79 if (connected) {
80 connected = false;
81 __sock->close();
85 const char *HttpURLConnection::getRequestMethod() const
87 return __method.c_str();
90 void HttpURLConnection::setRequestMethod(const char *method)
92 __method = method;
95 void HttpURLConnection::setRequestProperty(const char *key, const char *value)
97 if (__request == NULL) {
98 __request = new Fields;
100 __request->push_back(Field(key, value));
103 istream &HttpURLConnection::getInputStream()
105 if (!connected) {
106 connect();
107 setRequest();
109 return __sock->getInputStream();
112 ostream &HttpURLConnection::getOutputStream()
114 if (!connected) {
115 connect();
117 return __sock->getOutputStream();
120 void HttpURLConnection::setDoInput(bool doInput)
122 this->doInput = doInput;
125 void HttpURLConnection::setDoOutput(bool doOutput)
127 this->doOutput = doOutput;
130 void HttpURLConnection::connect()
132 if (!connected) {
133 int port = url.getPort();
134 if (port < 0) {
135 const char *protocol = url.getProtocol();
136 if (!stricmp(protocol, "http")) {
137 port = DEFAULT_PORT;
138 } else if (!stricmp(protocol, "ipp")) {
139 port = 631;
140 } else {
141 port = DEFAULT_PORT;
144 __sock = new Socket(url.getHost(), port);
145 if (__sock->fail()) {
146 __error_msg = __sock->getLastError();
147 } else {
148 connected = true;
153 const char *HttpURLConnection::getContentType()
155 return getHeaderField("Content-Type");
158 const char *HttpURLConnection::getContentEncoding()
160 return getHeaderField("Content-Encoding");
163 int HttpURLConnection::getContentLength()
165 const char *p = getHeaderField("Content-Length");
166 return p ? atoi(p) : -1;
169 const char *HttpURLConnection::getHeaderField(const char *s)
171 if (__response == NULL) {
172 action();
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();
181 return NULL;
184 HTTP_RESPONSECODE HttpURLConnection::getResponseCode()
186 if (__response == NULL) {
187 action();
189 return __response_code;
192 const char *HttpURLConnection::getResponseMessage()
194 if (__response == NULL) {
195 action();
197 return __response_message.c_str();
200 void HttpURLConnection::action()
202 if (!connected) {
203 connect();
205 if (connected) {
206 setRequest();
208 if (connected) {
209 getResponse();
213 void HttpURLConnection::setRequest()
215 if (connected) {
216 setRequestProperty("Host", url.getHost());
217 ostream &os = getOutputStream();
218 os << __method << ' ' << url.getFile() << " HTTP/1.1" << '\r' << '\n';
219 for (Fields::iterator it = __request->begin(); it != __request->end(); it++) {
220 os << (*it).key << ": " << (*it).value << '\r' << '\n';
222 os << '\r' << '\n';
224 setContent();
226 if (!doOutput) {
227 os.flush();
230 if (__response) {
231 delete __response;
232 __response = NULL;
237 void HttpURLConnection::setContent()
241 void HttpURLConnection::getResponse()
243 if (connected) {
245 if (__response == NULL) {
246 __response = new Fields;
248 istream &is = getInputStream();
250 char buffer[1024];
252 if (!is.getline(buffer, sizeof(buffer))) {
253 __error_msg = __sock->getLastError();
254 return;
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;
262 while (is.getline(buffer, sizeof(buffer))) {
263 if (buffer[0] == '\r') {
264 break;
266 buffer[is.gcount() - 2] = '\0';
267 __response->push_back(Field(buffer));
270 int size = getContentLength();
271 if (size > 0) {
272 getContent();
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;
285 switch (__response_code) {
286 case HTTP_MOVED_TEMP:
288 const char *p = getHeaderField("Location");
289 if (p) {
290 URL trueUrl(p);
291 url = trueUrl;
292 delete __response;
293 __response = NULL;
294 action();
297 break;
298 case HTTP_CONTINUE:
299 delete __response;
300 __response = NULL;
301 getResponse();
302 break;
303 default:
304 break;
310 void HttpURLConnection::getContent()
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;