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 13using namespace std; 14 15#define DEFAULT_PORT 80; 16 17Field::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 25Field::Field(const char *k, const char *v) 26{ 27 key = k ? k : ""; 28 value = v ? v : ""; 29} 30 31Field::Field(const Field &o) 32{ 33 key = o.key; 34 value = o.value; 35} 36 37Field &Field::operator = (const Field &o) 38{ 39 key = o.key; 40 value = o.value; 41 return *this; 42} 43 44bool Field::operator == (const Field &o) 45{ 46 return (key == o.key) && (value == o.value); 47} 48 49HttpURLConnection::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 59HttpURLConnection::~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 76void HttpURLConnection::disconnect() 77{ 78 if (connected) { 79 connected = false; 80 __sock->close(); 81 } 82} 83 84const char *HttpURLConnection::getRequestMethod() const 85{ 86 return __method.c_str(); 87} 88 89void HttpURLConnection::setRequestMethod(const char *method) 90{ 91 __method = method; 92} 93 94void 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 102istream &HttpURLConnection::getInputStream() 103{ 104 if (!connected) { 105 connect(); 106 setRequest(); 107 } 108 return __sock->getInputStream(); 109} 110 111ostream &HttpURLConnection::getOutputStream() 112{ 113 if (!connected) { 114 connect(); 115 } 116 return __sock->getOutputStream(); 117} 118 119void HttpURLConnection::setDoInput(bool doInput) 120{ 121 this->doInput = doInput; 122} 123 124void HttpURLConnection::setDoOutput(bool doOutput) 125{ 126 this->doOutput = doOutput; 127} 128 129void 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 152const char *HttpURLConnection::getContentType() 153{ 154 return getHeaderField("Content-Type"); 155} 156 157const char *HttpURLConnection::getContentEncoding() 158{ 159 return getHeaderField("Content-Encoding"); 160} 161 162int HttpURLConnection::getContentLength() 163{ 164 const char *p = getHeaderField("Content-Length"); 165 return p ? atoi(p) : -1; 166} 167 168const 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 183HTTP_RESPONSECODE HttpURLConnection::getResponseCode() 184{ 185 if (__response == NULL) { 186 action(); 187 } 188 return __response_code; 189} 190 191const char *HttpURLConnection::getResponseMessage() 192{ 193 if (__response == NULL) { 194 action(); 195 } 196 return __response_message.c_str(); 197} 198 199void HttpURLConnection::action() 200{ 201 if (!connected) { 202 connect(); 203 } 204 if (connected) { 205 setRequest(); 206 } 207 if (connected) { 208 getResponse(); 209 } 210} 211 212void 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 236void HttpURLConnection::setContent() 237{ 238} 239 240void 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 309void 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