Index: src/WebRequest.cpp |
=================================================================== |
--- a/src/WebRequest.cpp |
+++ b/src/WebRequest.cpp |
@@ -1,5 +1,190 @@ |
#include <AdblockPlus/WebRequest.h> |
AdblockPlus::WebRequest::~WebRequest() |
{ |
} |
+ |
+#if defined(HAVE_CURL) |
+ |
+#include <sstream> |
+#include <cctype> |
+#include <algorithm> |
+#include <curl/curl.h> |
+ |
+namespace |
+{ |
+ struct HeaderData |
+ { |
+ int status; |
+ bool expectingStatus; |
+ std::vector<std::string> headers; |
+ |
+ HeaderData() |
+ { |
+ status = 0; |
+ expectingStatus = true; |
+ } |
+ }; |
+ |
+ unsigned int ConvertErrorCode(CURLcode code) |
+ { |
+ switch (code) |
+ { |
+ case CURLE_OK: |
+ return NS_OK; |
+ case CURLE_FAILED_INIT: |
+ return NS_ERROR_NOT_INITIALIZED; |
+ case CURLE_UNSUPPORTED_PROTOCOL: |
+ return NS_ERROR_UNKNOWN_PROTOCOL; |
+ case CURLE_URL_MALFORMAT: |
+ return NS_ERROR_MALFORMED_URI; |
+ case CURLE_COULDNT_RESOLVE_PROXY: |
+ return NS_ERROR_UNKNOWN_PROXY_HOST; |
+ case CURLE_COULDNT_RESOLVE_HOST: |
+ return NS_ERROR_UNKNOWN_HOST; |
+ case CURLE_COULDNT_CONNECT: |
+ return NS_ERROR_CONNECTION_REFUSED; |
+ case CURLE_OUT_OF_MEMORY: |
+ return NS_ERROR_OUT_OF_MEMORY; |
+ case CURLE_OPERATION_TIMEDOUT: |
+ return NS_ERROR_NET_TIMEOUT; |
+ case CURLE_TOO_MANY_REDIRECTS: |
+ return NS_ERROR_REDIRECT_LOOP; |
+ case CURLE_GOT_NOTHING: |
+ return NS_ERROR_NO_CONTENT; |
+ case CURLE_SEND_ERROR: |
+ return NS_ERROR_NET_RESET; |
+ case CURLE_RECV_ERROR: |
+ return NS_ERROR_NET_RESET; |
+ default: |
+ return NS_CUSTOM_ERROR_BASE + code; |
+ } |
+ } |
+ |
+ size_t ReceiveData(char* ptr, size_t size, size_t nmemb, void* userdata) |
+ { |
+ std::stringstream* stream = static_cast<std::stringstream*>(userdata); |
+ stream->write(ptr, size * nmemb); |
+ return nmemb; |
+ } |
+ |
+ size_t ReceiveHeader(char* ptr, size_t size, size_t nmemb, void* userdata) |
+ { |
+ HeaderData* data = static_cast<HeaderData*>(userdata); |
+ std::string header(ptr, size * nmemb); |
+ if (data->expectingStatus) |
+ { |
+ // Parse the status code out of something like "HTTP/1.1 200 OK" |
Felix Dahlke
2013/04/12 03:53:50
I think using std::tr1::regex would be preferable.
Wladimir Palant
2013/04/12 13:39:32
See http://gcc.gnu.org/onlinedocs/libstdc++/manual
|
+ const std::string prefix("HTTP/1."); |
+ size_t prefixLen = prefix.length(); |
+ if (header.length() >= prefixLen + 2 && !header.compare(0, prefixLen, prefix) && |
+ isdigit(header[prefixLen]) && isspace(header[prefixLen + 1])) |
+ { |
+ size_t statusStart = prefixLen + 2; |
+ while (statusStart < header.length() && isspace(header[statusStart])) |
+ statusStart++; |
+ |
+ size_t statusEnd = statusStart; |
+ while (statusEnd < header.length() && isdigit(header[statusEnd])) |
+ statusEnd++; |
+ |
+ if (statusEnd > statusStart && statusEnd < header.length() && |
+ isspace(header[statusEnd])) |
+ { |
+ std::istringstream(header.substr(statusStart, statusEnd - statusStart)) >> data->status; |
+ data->headers.clear(); |
+ data->expectingStatus = false; |
+ } |
+ } |
+ } |
+ else |
+ { |
+ size_t headerEnd = header.length(); |
+ while (headerEnd > 0 && isspace(header[headerEnd - 1])) |
+ headerEnd--; |
+ |
+ if (headerEnd) |
+ data->headers.push_back(header.substr(0, headerEnd)); |
+ else |
+ data->expectingStatus = true; |
+ } |
+ return nmemb; |
+ } |
+} |
+ |
+AdblockPlus::ServerResponse AdblockPlus::DefaultWebRequest::GET( |
+ const std::string& url, const HeaderList& requestHeaders) const |
+{ |
+ AdblockPlus::ServerResponse result; |
+ result.status = NS_ERROR_NOT_INITIALIZED; |
+ result.responseStatus = 0; |
+ |
+ CURL *curl = curl_easy_init(); |
+ if (curl) |
+ { |
+ std::stringstream responseText; |
+ HeaderData headerData; |
+ curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); |
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); |
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ReceiveData); |
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseText); |
+ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, ReceiveHeader); |
+ curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headerData); |
+ |
+ struct curl_slist* headerList = 0; |
+ for (HeaderList::const_iterator it = requestHeaders.begin(); |
+ it != requestHeaders.end(); ++it) |
+ { |
+ curl_slist_append(headerList, (it->first + ": " + it->second).c_str()); |
Felix Dahlke
2013/04/12 03:53:50
According to the documentation, I think this shoul
|
+ } |
+ if (headerList) |
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerList); |
+ |
+ result.status = ConvertErrorCode(curl_easy_perform(curl)); |
+ result.responseStatus = headerData.status; |
+ result.responseText = responseText.str(); |
+ for (std::vector<std::string>::iterator it = headerData.headers.begin(); |
+ it != headerData.headers.end(); ++it) |
+ { |
+ // Parse header name and value out of something like "Foo: bar" |
Felix Dahlke
2013/04/12 03:53:50
I'd vote for std::tr1::regex here as well.
|
+ std::string header = *it; |
+ size_t colonPos = header.find(':'); |
+ if (colonPos != std::string::npos) |
+ { |
+ size_t nameStart = 0; |
+ size_t nameEnd = colonPos; |
+ while (nameEnd > nameStart && isspace(header[nameEnd - 1])) |
+ nameEnd--; |
+ |
+ size_t valueStart = colonPos + 1; |
+ while (valueStart < header.length() && isspace(header[valueStart])) |
+ valueStart++; |
+ size_t valueEnd = header.length(); |
+ |
+ if (nameEnd > nameStart && valueEnd > valueStart) |
+ { |
+ std::string name = header.substr(nameStart, nameEnd - nameStart); |
+ std::transform(name.begin(), name.end(), name.begin(), ::tolower); |
+ std::string value = header.substr(valueStart, valueEnd - valueStart); |
+ result.responseHeaders.push_back(std::pair<std::string, std::string>( |
+ name, value)); |
+ } |
+ } |
+ } |
+ |
+ if (headerList) |
+ curl_slist_free_all(headerList); |
+ curl_easy_cleanup(curl); |
+ } |
+ return result; |
+} |
+#else |
+AdblockPlus::ServerResponse AdblockPlus::DefaultWebRequest::GET( |
+ const std::string& url, const HeaderList& requestHeaders) const |
+{ |
+ AdblockPlus::ServerResponse result; |
+ result.status = NS_ERROR_FAILURE; |
+ result.responseStatus = 0; |
+ return result; |
+} |
+#endif |