// Sun, 18 Jun 2000 // Y.Takagi #include #include #include #define stricmp strcasecmp #include "HttpURLConnection.h" #include "Socket.h" using namespace std; #define DEFAULT_PORT 80; Field::Field(char *field) { char *p = strtok(field, ": \t\r\n"); key = p ? p : ""; p = strtok(NULL, " \t\r\n"); value = p ? p : ""; } Field::Field(const char *k, const char *v) { key = k ? k : ""; value = v ? v : ""; } Field::Field(const Field &o) { key = o.key; value = o.value; } Field &Field::operator = (const Field &o) { key = o.key; value = o.value; return *this; } bool Field::operator == (const Field &o) { return (key == o.key) && (value == o.value); } HttpURLConnection::HttpURLConnection(const URL &Url) : connected(false), doInput(true), doOutput(false), url(Url) { __sock = NULL; __method = "GET"; __request = NULL; __response = NULL; __response_code = HTTP_UNKNOWN; } HttpURLConnection::~HttpURLConnection() { disconnect(); if (__sock) { delete __sock; } if (__request) { delete __request; } if (__response) { delete __response; } } void HttpURLConnection::disconnect() { if (connected) { connected = false; __sock->close(); } } const char *HttpURLConnection::getRequestMethod() const { return __method.c_str(); } void HttpURLConnection::setRequestMethod(const char *method) { __method = method; } void HttpURLConnection::setRequestProperty(const char *key, const char *value) { if (__request == NULL) { __request = new Fields; } __request->push_back(Field(key, value)); } istream &HttpURLConnection::getInputStream() { if (!connected) { connect(); setRequest(); } return __sock->getInputStream(); } ostream &HttpURLConnection::getOutputStream() { if (!connected) { connect(); } return __sock->getOutputStream(); } void HttpURLConnection::setDoInput(bool doinput) { doinput = doinput; } void HttpURLConnection::setDoOutput(bool dooutput) { dooutput = dooutput; } void HttpURLConnection::connect() { if (!connected) { int port = url.getPort(); if (port < 0) { const char *protocol = url.getProtocol(); if (!stricmp(protocol, "http")) { port = DEFAULT_PORT; } else if (!stricmp(protocol, "ipp")) { port = 631; } else { port = DEFAULT_PORT; } } __sock = new Socket(url.getHost(), port); if (__sock->fail()) { __error_msg = __sock->getLastError(); } else { connected = true; } } } const char *HttpURLConnection::getContentType() { return getHeaderField("Content-Type"); } const char *HttpURLConnection::getContentEncoding() { return getHeaderField("Content-Encoding"); } int HttpURLConnection::getContentLength() { const char *p = getHeaderField("Content-Length"); return p ? atoi(p) : -1; } const char *HttpURLConnection::getHeaderField(const char *s) { if (__response == NULL) { action(); } if (__response) { for (Fields::iterator it = __response->begin(); it != __response->end(); it++) { if ((*it).key == s) { return (*it).value.c_str(); } } } return NULL; } HTTP_RESPONSECODE HttpURLConnection::getResponseCode() { if (__response == NULL) { action(); } return __response_code; } const char *HttpURLConnection::getResponseMessage() { if (__response == NULL) { action(); } return __response_message.c_str(); } void HttpURLConnection::action() { if (!connected) { connect(); } if (connected) { setRequest(); } if (connected) { getResponse(); } } void HttpURLConnection::setRequest() { if (connected) { setRequestProperty("Host", url.getHost()); ostream &os = getOutputStream(); os << __method << ' ' << url.getFile() << " HTTP/1.1" << '\r' << '\n'; for (Fields::iterator it = __request->begin(); it != __request->end(); it++) { os << (*it).key << ": " << (*it).value << '\r' << '\n'; } os << '\r' << '\n'; setContent(); if (!doOutput) { os.flush(); } if (__response) { delete __response; __response = NULL; } } } void HttpURLConnection::setContent() { } void HttpURLConnection::getResponse() { if (connected) { if (__response == NULL) { __response = new Fields; istream &is = getInputStream(); char buffer[1024]; if (!is.getline(buffer, sizeof(buffer))) { __error_msg = __sock->getLastError(); return; } buffer[is.gcount() - 2] = '\0'; __response_message = buffer; strtok(buffer, " "); char *p = strtok(NULL, " "); __response_code = p ? (HTTP_RESPONSECODE)atoi(p) : HTTP_UNKNOWN; while (is.getline(buffer, sizeof(buffer))) { if (buffer[0] == '\r') { break; } buffer[is.gcount() - 2] = '\0'; __response->push_back(Field(buffer)); } int size = getContentLength(); if (size > 0) { getContent(); } if (__response_code != HTTP_CONTINUE) { const char *s = getHeaderField("Connection"); if (s == NULL) { connected = false; __error_msg = "cannot found \"Connection\" field"; } else if (stricmp(s, "Keep-Alive")) { connected = false; } } switch (__response_code) { case HTTP_MOVED_TEMP: { const char *p = getHeaderField("Location"); if (p) { URL trueUrl(p); url = trueUrl; delete __response; __response = NULL; action(); } } break; case HTTP_CONTINUE: delete __response; __response = NULL; getResponse(); break; default: break; } } } } void HttpURLConnection::getContent() { const int maxBufSize = 1024; if (connected) { int size = getContentLength(); if (size > 0) { istream &is = getInputStream(); int bufsize = min(size, maxBufSize); char buf[maxBufSize]; while (size > 0 && is.read(buf, bufsize)) { size -= bufsize; } } } }