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