Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: src/DefaultWebRequestDummy.cpp

Issue 10252013: Implemented curl support for web requests (Closed)
Left Patch Set: Created April 11, 2013, 3:52 p.m.
Right Patch Set: Addressed review comments Created April 12, 2013, 1:37 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Right: Side by side diff | Download
LEFTRIGHT
(no file at all)
1 #include <AdblockPlus/WebRequest.h> 1 #include <AdblockPlus/WebRequest.h>
2 2
3 AdblockPlus::WebRequest::~WebRequest()
4 {
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 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());
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"
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( 3 AdblockPlus::ServerResponse AdblockPlus::DefaultWebRequest::GET(
183 const std::string& url, const HeaderList& requestHeaders) const 4 const std::string& url, const HeaderList& requestHeaders) const
184 { 5 {
185 AdblockPlus::ServerResponse result; 6 AdblockPlus::ServerResponse result;
186 result.status = NS_ERROR_FAILURE; 7 result.status = NS_ERROR_FAILURE;
187 result.responseStatus = 0; 8 result.responseStatus = 0;
188 return result; 9 return result;
189 } 10 }
190 #endif
LEFTRIGHT

Powered by Google App Engine
This is Rietveld