#include #include #include #include t_headers no_headers; HttpClient::HttpClient(const String & _url, Handle * _out, const String & _fake_host, t_headers _headers) : url(_url), out(_out), fake_host(_fake_host), headers(_headers), host(""), uri("") { DecodeURL(); Client.SetNonBlock(); Client.Connect(host, 80); if (Client.IsConnected()) { SetBurst(); } else { WaitFor(&Client, W4_WRITING); } } HttpClient::~HttpClient() { } int HttpClient::Do() throw (GeneralException) { t_headers::iterator i; String t; int l; Regex h_reply("^HTTP/1.1 "); Regex chunked_header("^Transfer-Encoding: chunked$"); switch (current) { case 0: if (Client.IsConnecting()) { Client.FinalizeConnect(); } if (!Client.IsConnected()) { return TASK_DONE; } current = 1; case 1: b << "GET " + uri + " HTTP/1.1\r\n" "Host: " + (fake_host == "" ? host : fake_host) + "\r\n" "Connection: close\r\n"; for (i = headers.begin(); i != headers.end(); i++) { b << *i + "\r\n"; } b << "\r\n"; c = new CopyJob(&b, &Client); WaitFor(c); current = 2; Suspend(TASK_ON_HOLD); case 2: delete c; c = new ReadJob(&Client, &b); WaitFor(c); current = 3; Suspend(TASK_ON_HOLD); case 3: delete c; b >> t; if (!h_reply.Match(t)) { http_code = 0; status = "Invalid answer from HTTP server."; return TASK_DONE; } reply = t.extract(9); chunked = false; while (t.strlen()) { b >> t; reply_headers.push_back(t); if (chunked_header.Match(t)) { chunked = true; } } http_code = reply.to_int(); if (http_code != 200) { status = "Reply code != 200."; return TASK_DONE; } status = "Downloading."; if (!chunked) { current = 6; c = new CopyJob(&Client, out); WaitFor(c); Suspend(TASK_ON_HOLD); } c = 0; case 4: if (c) delete c; c = new ReadJob(&Client, &b, any); WaitFor(c); current = 5; Suspend(TASK_ON_HOLD); case 5: delete c; b >> t; if (t.strlen() == 0) { current = 4; c = 0; Suspend(TASK_BURST); } l = t.to_int("%x"); if (l == 0) { status = "Downloaded."; return TASK_DONE; } c = new CopyJob(&Client, out, l); WaitFor(c); current = 4; Suspend(TASK_ON_HOLD); case 6: delete c; status = "Downloaded."; return TASK_DONE; } return TASK_ON_HOLD; } String HttpClient::GetStatus() { return status; } void HttpClient::DecodeURL() throw (GeneralException) { int p; static const Regex isURLValid("^http://[^/]"); if (!isURLValid.Match(url)) throw GeneralException("Invalid URL."); String tmp = url.extract(7); p = tmp.strchr('/'); if (p < 0) { host = tmp; return; } host = tmp.extract(0, p - 1); uri = tmp.extract(p); }