X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_http_client.cpp;h=5ddd6ddbd92a849f770e92fde85dff01c21a63c2;hb=7c197db72eab03321e4f3e847054e13126520504;hp=962ecfc17a4c2f74a82cc2a23ef788d7eedaec01;hpb=bc341bfc390154919652271047cbea9b4a14426b;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_http_client.cpp b/src/modules/m_http_client.cpp index 962ecfc17..5ddd6ddbd 100644 --- a/src/modules/m_http_client.cpp +++ b/src/modules/m_http_client.cpp @@ -1,4 +1,4 @@ -/* +------------------------------------+ +;/* +------------------------------------+ * | Inspire Internet Relay Chat Daemon | * +------------------------------------+ * @@ -34,11 +34,12 @@ class HTTPSocket : public InspSocket private: InspIRCd *Server; class ModuleHTTPClient *Mod; - HTTPClientRequest *req; + HTTPClientRequest req; HTTPClientResponse *response; URL url; enum { HTTP_CLOSED, HTTP_REQSENT, HTTP_HEADERS, HTTP_DATA } status; std::string data; + std::string buffer; public: HTTPSocket(InspIRCd *Instance, class ModuleHTTPClient *Mod); @@ -56,17 +57,20 @@ class HTTPResolver : public Resolver private: HTTPSocket *socket; public: - HTTPResolver(HTTPSocket *socket, InspIRCd *Instance, const string &hostname) : Resolver(Instance, hostname, DNS_QUERY_FORWARD), socket(socket) + HTTPResolver(HTTPSocket *socket, InspIRCd *Instance, const string &hostname, bool &cached, Module* me) : Resolver(Instance, hostname, DNS_QUERY_FORWARD, cached, me), socket(socket) { + ServerInstance->Log(DEBUG,"Resolving "+hostname); } - void OnLookupComplete(const string &result) + void OnLookupComplete(const string &result, unsigned int ttl, bool cached) { + ServerInstance->Log(DEBUG,"Resolver done"); socket->Connect(result); } void OnError(ResolverError e, const string &errmsg) { + ServerInstance->Log(DEBUG,"Resolver error"); delete socket; } }; @@ -98,21 +102,18 @@ class ModuleHTTPClient : public Module { List[I_OnRequest] = 1; } - - char *OnRequest(Request *req) + + char* OnRequest(Request *req) { - HTTPClientRequest *httpreq = (HTTPClientRequest *) req->GetData(); - HTTPSocket *sock = new HTTPSocket(ServerInstance, this); - sock->DoRequest(httpreq); - // No return value + HTTPClientRequest *httpreq = (HTTPClientRequest *)req; + if (!strcmp(httpreq->GetId(), HTTP_CLIENT_REQUEST)) + { + HTTPSocket *sock = new HTTPSocket(ServerInstance, this); + sock->DoRequest(httpreq); + // No return value + } return NULL; } - - void SendReply(Module *to, HTTPClientResponse *data) - { - Request req((char *) data, this, to); - req.Send(); - } }; HTTPSocket::HTTPSocket(InspIRCd *Instance, ModuleHTTPClient *Mod) @@ -137,17 +138,35 @@ HTTPSocket::~HTTPSocket() bool HTTPSocket::DoRequest(HTTPClientRequest *req) { - this->req = req; - - if (!ParseURL(req->GetURL())) + /* Tweak by brain - we take a copy of this, + * so that the caller doesnt need to leave + * pointers knocking around, less chance of + * a memory leak. + */ + this->req = *req; + + Instance->Log(DEBUG,"Request in progress"); + + if (!ParseURL(this->req.GetURL())) + { + Instance->Log(DEBUG,"Parse failed"); return false; + } this->port = url.port; strlcpy(this->host, url.domain.c_str(), MAXBUF); - if (!inet_aton(this->host, &this->addy)) + in_addr addy1; +#ifdef IPV6 + in6_addr addy2; + if ((inet_aton(this->host, &addy1) > 0) || (inet_pton(AF_INET6, this->host, &addy2) > 0)) +#else + if (inet_aton(this->host, &addy1) > 0) +#endif { - new HTTPResolver(this, Server, url.domain); + bool cached; + HTTPResolver* r = new HTTPResolver(this, Server, url.domain, cached, (Module*)Mod); + Instance->AddResolver(r, cached); return true; } else @@ -162,60 +181,79 @@ bool HTTPSocket::ParseURL(const std::string &iurl) { url.url = iurl; url.port = 80; + url.protocol = "http"; + + irc::sepstream tokenizer(iurl, '/'); - // Tokenize by slashes (protocol:, blank, domain, request..) - int pos = 0, pstart = 0, pend = 0; - - for (; ; pend = url.url.find('/', pstart)) + for (int p = 0;; p++) { - string part = url.url.substr(pstart, pend); - - switch (pos) + std::string part = tokenizer.GetToken(); + if (part.empty() && tokenizer.StreamEnd()) + break; + + if ((p == 0) && (part[part.length() - 1] == ':')) { - case 0: - // Protocol - if (part[part.length()-1] != ':') - return false; - url.protocol = part.substr(0, part.length() - 1); - break; - case 1: - // Empty, skip - break; - case 2: - // User and password (user:pass@) - string::size_type aend = part.find('@', 0); - if (aend != string::npos) + // Protocol ('http:') + url.protocol = part.substr(0, part.length() - 1); + } + else if ((p == 1) && (part.empty())) + { + continue; + } + else if (url.domain.empty()) + { + // Domain part: [user[:pass]@]domain[:port] + std::string::size_type usrpos = part.find('@'); + if (usrpos != std::string::npos) + { + // Have a user (and possibly password) part + std::string::size_type ppos = part.find(':'); + if ((ppos != std::string::npos) && (ppos < usrpos)) { - // Technically, it is valid to not have a password (username@domain) - string::size_type usrend = part.find(':', 0); - - if ((usrend != string::npos) && (usrend < aend)) - url.password = part.substr(usrend + 1, aend); - else - usrend = aend; - - url.username = part.substr(0, usrend); + // Have password too + url.password = part.substr(ppos + 1, usrpos - ppos - 1); + url.username = part.substr(0, ppos); } else - aend = 0; - - // Port (:port) - string::size_type dend = part.find(':', aend); - if (dend != string::npos) - url.port = atoi(part.substr(dend + 1).c_str()); - - // Domain - url.domain = part.substr(aend + 1, dend); + { + url.username = part.substr(0, usrpos); + } - // The rest of the string is the request - url.request = url.url.substr(pend); - break; + part = part.substr(usrpos + 1); + } + + std::string::size_type popos = part.rfind(':'); + if (popos != std::string::npos) + { + url.port = atoi(part.substr(popos + 1).c_str()); + url.domain = part.substr(0, popos); + } + else + { + url.domain = part; + } } - - if (pos++ == 2) - break; + else + { + // Request (part of it).. + url.request.append("/"); + url.request.append(part); + } + } + + if (url.request.empty()) + url.request = "/"; - pstart = pend + 1; + if ((url.domain.empty()) || (!url.port) || (url.protocol.empty())) + { + Instance->Log(DEFAULT, "Invalid URL (%s): Missing required value", iurl.c_str()); + return false; + } + + if (url.protocol != "http") + { + Instance->Log(DEFAULT, "Invalid URL (%s): Unsupported protocol '%s'", iurl.c_str(), url.protocol.c_str()); + return false; } return true; @@ -227,7 +265,6 @@ void HTTPSocket::Connect(const string &ip) if (!this->DoConnect()) { - Server->Log(DEBUG, "Unable to connect HTTPSocket to %s", this->host); delete this; } } @@ -237,7 +274,7 @@ bool HTTPSocket::OnConnected() std::string request = "GET " + url.request + " HTTP/1.1\r\n"; // Dump headers into the request - HeaderMap headers = req->GetHeaders(); + HeaderMap headers = req.GetHeaders(); for (HeaderMap::iterator i = headers.begin(); i != headers.end(); i++) request += i->first + ": " + i->second + "\r\n"; @@ -263,58 +300,69 @@ bool HTTPSocket::OnDataReady() this->Close(); return false; } - - // Needs buffering for incomplete reads.. - char *lend; - + if (this->status < HTTP_DATA) { - while ((lend = strstr(data, "\r\n")) != NULL) + std::string line; + std::string::size_type pos; + + this->buffer += data; + while ((pos = buffer.find("\r\n")) != std::string::npos) { - if (strncmp(data, "\r\n", 2) == 0) + line = buffer.substr(0, pos); + buffer = buffer.substr(pos + 2); + if (line.empty()) { this->status = HTTP_DATA; + this->data += this->buffer; + this->buffer = ""; break; } - - *lend = '\0'; +// while ((line = buffer.sstrstr(data, "\r\n")) != NULL) +// { +// if (strncmp(data, "\r\n", 2) == 0) if (this->status == HTTP_REQSENT) { // HTTP reply (HTTP/1.1 200 msg) + char const* data = line.c_str(); data += 9; - response = new HTTPClientResponse(url.url, atoi(data), data + 4); + response = new HTTPClientResponse((Module*)Mod, req.GetSource() , url.url, atoi(data), data + 4); this->status = HTTP_HEADERS; continue; } - char *hdata = strchr(data, ':'); + if ((pos = line.find(':')) != std::string::npos) + { + +// char *hdata = strchr(data, ':'); - if (!hdata) - continue; +// if (!hdata) +// continue; - *hdata = '\0'; +// *hdata = '\0'; - response->AddHeader(data, hdata + 2); +// response->AddHeader(data, hdata + 2); + response->AddHeader(line.substr(0, pos), line.substr(pos + 1)); - data = lend + 2; +// data = lend + 2; + } else + continue; } + } else { + this->data += data; } - - this->data += data; return true; } void HTTPSocket::OnClose() { - if (!data.length()) - { - Server->Log(DEBUG, "HTTP socket closed unexpectedly (no content recieved)"); - return; - } - Server->Log(DEBUG, "Got file from HTTP successfully"); + if (data.empty()) + return; // notification that request failed? + response->data = data; - Mod->SendReply(req->GetSrc(), response); + response->Send(); + delete response; } class ModuleHTTPClientFactory : public ModuleFactory @@ -338,5 +386,3 @@ extern "C" void *init_module(void) { return new ModuleHTTPClientFactory; } - -