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