Left: | ||
Right: |
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" | |
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
| |
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 HeaderList& 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* headerList = 0; | |
135 for (HeaderList::const_iterator it = requestHeaders.begin(); | |
136 it != requestHeaders.end(); ++it) | |
137 { | |
138 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
| |
139 } | |
140 if (headerList) | |
141 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerList); | |
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" | |
Felix Dahlke
2013/04/12 03:53:50
I'd vote for std::tr1::regex here as well.
| |
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 (headerList) | |
176 curl_slist_free_all(headerList); | |
177 curl_easy_cleanup(curl); | |
178 } | |
179 return result; | |
180 } | |
181 #else | |
182 AdblockPlus::ServerResponse AdblockPlus::DefaultWebRequest::GET( | |
183 const std::string& url, const HeaderList& 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 |