OLD | NEW |
1 #include <AdblockPlus/WebRequest.h> | 1 #include <AdblockPlus/WebRequest.h> |
2 | 2 |
3 AdblockPlus::WebRequest::~WebRequest() | 3 AdblockPlus::WebRequest::~WebRequest() |
4 { | 4 { |
5 } | 5 } |
| 6 |
| 7 #if defined(HAVE_CURL) |
| 8 |
| 9 #include <sstream> |
| 10 #include <cctype> |
| 11 #include <algorithm> |
| 12 #include <curl/curl.h> |
| 13 |
| 14 namespace |
| 15 { |
| 16 struct HeaderData |
| 17 { |
| 18 int status; |
| 19 bool expectingStatus; |
| 20 std::vector<std::string> headers; |
| 21 |
| 22 HeaderData() |
| 23 { |
| 24 status = 0; |
| 25 expectingStatus = true; |
| 26 } |
| 27 }; |
| 28 |
| 29 unsigned int ConvertErrorCode(CURLcode code) |
| 30 { |
| 31 switch (code) |
| 32 { |
| 33 case CURLE_OK: |
| 34 return NS_OK; |
| 35 case CURLE_FAILED_INIT: |
| 36 return NS_ERROR_NOT_INITIALIZED; |
| 37 case CURLE_UNSUPPORTED_PROTOCOL: |
| 38 return NS_ERROR_UNKNOWN_PROTOCOL; |
| 39 case CURLE_URL_MALFORMAT: |
| 40 return NS_ERROR_MALFORMED_URI; |
| 41 case CURLE_COULDNT_RESOLVE_PROXY: |
| 42 return NS_ERROR_UNKNOWN_PROXY_HOST; |
| 43 case CURLE_COULDNT_RESOLVE_HOST: |
| 44 return NS_ERROR_UNKNOWN_HOST; |
| 45 case CURLE_COULDNT_CONNECT: |
| 46 return NS_ERROR_CONNECTION_REFUSED; |
| 47 case CURLE_OUT_OF_MEMORY: |
| 48 return NS_ERROR_OUT_OF_MEMORY; |
| 49 case CURLE_OPERATION_TIMEDOUT: |
| 50 return NS_ERROR_NET_TIMEOUT; |
| 51 case CURLE_TOO_MANY_REDIRECTS: |
| 52 return NS_ERROR_REDIRECT_LOOP; |
| 53 case CURLE_GOT_NOTHING: |
| 54 return NS_ERROR_NO_CONTENT; |
| 55 case CURLE_SEND_ERROR: |
| 56 return NS_ERROR_NET_RESET; |
| 57 case CURLE_RECV_ERROR: |
| 58 return NS_ERROR_NET_RESET; |
| 59 default: |
| 60 return NS_CUSTOM_ERROR_BASE + code; |
| 61 } |
| 62 } |
| 63 |
| 64 size_t ReceiveData(char* ptr, size_t size, size_t nmemb, void* userdata) |
| 65 { |
| 66 std::stringstream* stream = static_cast<std::stringstream*>(userdata); |
| 67 stream->write(ptr, size * nmemb); |
| 68 return nmemb; |
| 69 } |
| 70 |
| 71 size_t ReceiveHeader(char* ptr, size_t size, size_t nmemb, void* userdata) |
| 72 { |
| 73 HeaderData* data = static_cast<HeaderData*>(userdata); |
| 74 std::string header(ptr, size * nmemb); |
| 75 if (data->expectingStatus) |
| 76 { |
| 77 // Parse the status code out of something like "HTTP/1.1 200 OK" |
| 78 const std::string prefix("HTTP/1."); |
| 79 size_t prefixLen = prefix.length(); |
| 80 if (header.length() >= prefixLen + 2 && !header.compare(0, prefixLen, pref
ix) && |
| 81 isdigit(header[prefixLen]) && isspace(header[prefixLen + 1])) |
| 82 { |
| 83 size_t statusStart = prefixLen + 2; |
| 84 while (statusStart < header.length() && isspace(header[statusStart])) |
| 85 statusStart++; |
| 86 |
| 87 size_t statusEnd = statusStart; |
| 88 while (statusEnd < header.length() && isdigit(header[statusEnd])) |
| 89 statusEnd++; |
| 90 |
| 91 if (statusEnd > statusStart && statusEnd < header.length() && |
| 92 isspace(header[statusEnd])) |
| 93 { |
| 94 std::istringstream(header.substr(statusStart, statusEnd - statusStart)
) >> data->status; |
| 95 data->headers.clear(); |
| 96 data->expectingStatus = false; |
| 97 } |
| 98 } |
| 99 } |
| 100 else |
| 101 { |
| 102 size_t headerEnd = header.length(); |
| 103 while (headerEnd > 0 && isspace(header[headerEnd - 1])) |
| 104 headerEnd--; |
| 105 |
| 106 if (headerEnd) |
| 107 data->headers.push_back(header.substr(0, headerEnd)); |
| 108 else |
| 109 data->expectingStatus = true; |
| 110 } |
| 111 return nmemb; |
| 112 } |
| 113 } |
| 114 |
| 115 AdblockPlus::ServerResponse AdblockPlus::DefaultWebRequest::GET( |
| 116 const std::string& url, const HeadersList& requestHeaders) const |
| 117 { |
| 118 AdblockPlus::ServerResponse result; |
| 119 result.status = NS_ERROR_NOT_INITIALIZED; |
| 120 result.responseStatus = 0; |
| 121 |
| 122 CURL *curl = curl_easy_init(); |
| 123 if (curl) |
| 124 { |
| 125 std::stringstream responseText; |
| 126 HeaderData headerData; |
| 127 curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); |
| 128 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); |
| 129 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ReceiveData); |
| 130 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseText); |
| 131 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, ReceiveHeader); |
| 132 curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headerData); |
| 133 |
| 134 struct curl_slist* headersList = 0; |
| 135 for (HeadersList::const_iterator it = requestHeaders.begin(); |
| 136 it != requestHeaders.end(); ++it) |
| 137 { |
| 138 curl_slist_append(headersList, (it->first + ": " + it->second).c_str()); |
| 139 } |
| 140 if (headersList) |
| 141 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headersList); |
| 142 |
| 143 result.status = ConvertErrorCode(curl_easy_perform(curl)); |
| 144 result.responseStatus = headerData.status; |
| 145 result.responseText = responseText.str(); |
| 146 for (std::vector<std::string>::iterator it = headerData.headers.begin(); |
| 147 it != headerData.headers.end(); ++it) |
| 148 { |
| 149 // Parse header name and value out of something like "Foo: bar" |
| 150 std::string header = *it; |
| 151 size_t colonPos = header.find(':'); |
| 152 if (colonPos != std::string::npos) |
| 153 { |
| 154 size_t nameStart = 0; |
| 155 size_t nameEnd = colonPos; |
| 156 while (nameEnd > nameStart && isspace(header[nameEnd - 1])) |
| 157 nameEnd--; |
| 158 |
| 159 size_t valueStart = colonPos + 1; |
| 160 while (valueStart < header.length() && isspace(header[valueStart])) |
| 161 valueStart++; |
| 162 size_t valueEnd = header.length(); |
| 163 |
| 164 if (nameEnd > nameStart && valueEnd > valueStart) |
| 165 { |
| 166 std::string name = header.substr(nameStart, nameEnd - nameStart); |
| 167 std::transform(name.begin(), name.end(), name.begin(), ::tolower); |
| 168 std::string value = header.substr(valueStart, valueEnd - valueStart); |
| 169 result.responseHeaders.push_back(std::pair<std::string, std::string>( |
| 170 name, value)); |
| 171 } |
| 172 } |
| 173 } |
| 174 |
| 175 if (headersList) |
| 176 curl_slist_free_all(headersList); |
| 177 curl_easy_cleanup(curl); |
| 178 } |
| 179 return result; |
| 180 } |
| 181 #else |
| 182 AdblockPlus::ServerResponse AdblockPlus::DefaultWebRequest::GET( |
| 183 const std::string& url, const HeadersList& requestHeaders) const |
| 184 { |
| 185 AdblockPlus::ServerResponse result; |
| 186 result.status = NS_ERROR_FAILURE; |
| 187 result.responseStatus = 0; |
| 188 return result; |
| 189 } |
| 190 #endif |
OLD | NEW |