Line data Source code
1 : /*
2 : * Packge : Wilt
3 : * Author : S. Hamblett <steve.hamblett@linux.com>
4 : * Date : 04/06/2013
5 : * Copyright : S.Hamblett@OSCF
6 : *
7 : * Browser(dart:html) CouchDB HTTP adapter for Wilt.
8 : *
9 : * This always returns a JSON Object the format of which is documented in
10 : * the Result Interface document
11 : *
12 : */
13 :
14 : part of wilt_server_client;
15 :
16 : class WiltServerHTTPAdapter implements WiltHTTPAdapter {
17 : /// User for change notification authorization
18 : String _user;
19 :
20 : /// Password for change notification authorization
21 : String _password;
22 :
23 : /// Auth Type for change notification authorization
24 : String _authType;
25 :
26 : /// HTTP client
27 : http.Client _client;
28 :
29 : /// Construction
30 1 : WiltServerHTTPAdapter() {
31 2 : _client = new http.Client();
32 : }
33 :
34 : /// Processes the HTTP request, returning the server's response
35 : /// as a future
36 : Future<jsonobject.JsonObject> httpRequest(String method, String url,
37 : [String data = null, Map headers = null]) {
38 : /**
39 : * Initialise
40 : */
41 1 : final Completer completer = new Completer();
42 :
43 : /// Successful completion
44 : void onSuccess(http.Response response) {
45 : /**
46 : * Process the success response, note that an error response from CouchDB is
47 : * treated as an error, not as a success with an 'error' field in it.
48 : */
49 1 : final jsonobject.JsonObject jsonResponse = new jsonobject.JsonObject();
50 1 : jsonResponse.error = false;
51 1 : jsonResponse.errorCode = 0;
52 1 : jsonResponse.successText = null;
53 1 : jsonResponse.errorText = null;
54 1 : jsonResponse.allResponseHeader = null;
55 1 : jsonResponse.method = method;
56 2 : jsonResponse.responseText = response.body;
57 :
58 : /**
59 : * Check the header, if application/json try and decode it,
60 : * otherwise its just raw data, ie an attachment.
61 : */
62 2 : if (response.headers.containsValue('application/json')) {
63 : var couchResp;
64 : try {
65 2 : couchResp = JSON.decode(response.body);
66 : } catch (e) {
67 1 : jsonResponse.error = true;
68 1 : final jsonobject.JsonObject errorAsJson = new jsonobject.JsonObject();
69 1 : errorAsJson.error = "JSON Decode Error";
70 1 : errorAsJson.reason = "None";
71 1 : jsonResponse.jsonCouchResponse = errorAsJson;
72 : /* Set the response headers */
73 2 : jsonResponse.allResponseHeaders = response.headers;
74 : /**
75 : * Complete the request
76 : */
77 2 : if (!completer.isCompleted) completer.complete(jsonResponse);
78 : }
79 :
80 2 : if ((couchResp is Map) && (couchResp.containsKey('error'))) {
81 1 : jsonResponse.error = true;
82 1 : final jsonobject.JsonObject errorAsJson = new jsonobject.JsonObject();
83 1 : errorAsJson.error = "CouchDb Error";
84 2 : errorAsJson.reason = couchResp['reason'];
85 1 : jsonResponse.jsonCouchResponse = errorAsJson;
86 : /* Set the response headers */
87 2 : jsonResponse.allResponseHeaders = response.headers;
88 : /**
89 : * Complete the request
90 : */
91 2 : if (!completer.isCompleted) completer.complete(jsonResponse);
92 : }
93 :
94 : /**
95 : * Success response
96 : */
97 1 : if (method != Wilt.headd) {
98 : final jsonobject.JsonObject successAsJson =
99 2 : new jsonobject.JsonObject.fromJsonString(response.body);
100 1 : jsonResponse.jsonCouchResponse = successAsJson;
101 : }
102 : } else {
103 1 : final jsonobject.JsonObject successAsJson = new jsonobject.JsonObject();
104 1 : successAsJson.ok = true;
105 3 : successAsJson.contentType = response.headers['content-type'];
106 1 : jsonResponse.jsonCouchResponse = successAsJson;
107 : }
108 :
109 : /* Set the response headers */
110 2 : jsonResponse.allResponseHeaders = response.headers;
111 : /**
112 : * Complete the request
113 : */
114 2 : if (!completer.isCompleted) completer.complete(jsonResponse);
115 : }
116 :
117 : /// Successful completion for Copy
118 : void onCopySuccess(http.StreamedResponse response) {
119 : /**
120 : * Process the success response, note that an error response from CouchDB is
121 : * treated as an error, not as a success with an 'error' field in it.
122 : */
123 1 : final jsonobject.JsonObject jsonResponse = new jsonobject.JsonObject();
124 1 : jsonResponse.error = false;
125 1 : jsonResponse.errorCode = 0;
126 1 : jsonResponse.successText = null;
127 1 : jsonResponse.errorText = null;
128 1 : jsonResponse.allResponseHeader = null;
129 1 : jsonResponse.method = method;
130 3 : response.stream.bytesToString(UTF8).then((String text) {
131 1 : jsonResponse.responseText = text;
132 :
133 : /**
134 : * Check the header, if application/json try and decode it,
135 : * otherwise its just raw data, ie an attachment.
136 : */
137 2 : if (response.headers.containsValue('application/json')) {
138 : var couchResp;
139 : try {
140 1 : couchResp = JSON.decode(text);
141 : } catch (e) {
142 0 : jsonResponse.error = true;
143 : final jsonobject.JsonObject errorAsJson =
144 0 : new jsonobject.JsonObject();
145 0 : errorAsJson.error = "JSON Decode Error";
146 0 : errorAsJson.reason = "None";
147 0 : jsonResponse.jsonCouchResponse = errorAsJson;
148 : /* Set the response headers */
149 0 : jsonResponse.allResponseHeaders = response.headers;
150 : /**
151 : * Complete the request
152 : */
153 0 : if (!completer.isCompleted) completer.complete(jsonResponse);
154 : }
155 :
156 2 : if ((couchResp is Map) && (couchResp.containsKey('error'))) {
157 0 : jsonResponse.error = true;
158 : final jsonobject.JsonObject errorAsJson =
159 0 : new jsonobject.JsonObject();
160 0 : errorAsJson.error = "CouchDb Error";
161 0 : errorAsJson.reason = couchResp['reason'];
162 0 : jsonResponse.jsonCouchResponse = errorAsJson;
163 : /* Set the response headers */
164 0 : jsonResponse.allResponseHeaders = response.headers;
165 : /**
166 : * Complete the reequest
167 : */
168 0 : if (!completer.isCompleted) completer.complete(jsonResponse);
169 : }
170 :
171 : /**
172 : * Success response
173 : */
174 1 : if (method != Wilt.headd) {
175 : final jsonobject.JsonObject successAsJson =
176 1 : new jsonobject.JsonObject.fromJsonString(text);
177 1 : jsonResponse.jsonCouchResponse = successAsJson;
178 : }
179 : } else {
180 : final jsonobject.JsonObject successAsJson =
181 0 : new jsonobject.JsonObject();
182 0 : successAsJson.ok = true;
183 0 : successAsJson.contentType = response.headers['content-type'];
184 0 : jsonResponse.jsonCouchResponse = successAsJson;
185 : }
186 :
187 : /* Set the response headers */
188 2 : jsonResponse.allResponseHeaders = response.headers;
189 :
190 : /**
191 : * Complete the request
192 : */
193 2 : if (!completer.isCompleted) completer.complete(jsonResponse);
194 : });
195 : }
196 :
197 : /// Error completion
198 : void onError(http.ClientException response) {
199 : /* Process the error response */
200 1 : final jsonobject.JsonObject jsonResponse = new jsonobject.JsonObject();
201 1 : jsonResponse.method = method;
202 1 : jsonResponse.error = true;
203 1 : jsonResponse.successText = null;
204 1 : jsonResponse.errorCode = 0;
205 1 : final jsonobject.JsonObject errorAsJson = new jsonobject.JsonObject();
206 1 : errorAsJson.error = "Invalid HTTP response";
207 2 : errorAsJson.reason = response.message;
208 1 : jsonResponse.jsonCouchResponse = errorAsJson;
209 :
210 : /**
211 : * Complete the request
212 : */
213 2 : if (!completer.isCompleted) completer.complete(jsonResponse);
214 : }
215 :
216 : /**
217 : * Condition the input method string to get the HTTP method
218 : */
219 1 : final List temp = method.split('_');
220 1 : final String httpMethod = temp[0];
221 :
222 : /**
223 : * Set the content type header correctly
224 : */
225 1 : if (headers.containsKey('Content-Type')) {
226 1 : final String contentType = headers['Content-Type'];
227 1 : headers.remove('Content-Type');
228 1 : headers['content-type'] = contentType;
229 : }
230 : /**
231 : * Query CouchDB over HTTP
232 : */
233 1 : if (httpMethod == "GET") {
234 3 : _client.get(url, headers: headers).then(onSuccess, onError: onError);
235 1 : } else if (httpMethod == "PUT") {
236 1 : _client
237 1 : .put(url, headers: headers, body: data)
238 1 : .then(onSuccess, onError: onError);
239 1 : } else if (httpMethod == "POST") {
240 1 : _client
241 1 : .post(url, headers: headers, body: data)
242 1 : .then(onSuccess, onError: onError);
243 1 : } else if (httpMethod == "HEAD") {
244 3 : _client.head(url, headers: headers).then(onSuccess, onError: onError);
245 1 : } else if (httpMethod == "DELETE") {
246 3 : _client.delete(url, headers: headers).then(onSuccess, onError: onError);
247 1 : } else if (httpMethod == "COPY") {
248 1 : final Uri encodedUrl = Uri.parse(url);
249 1 : final request = new http.Request("COPY", encodedUrl);
250 2 : request.headers.addAll(headers);
251 3 : _client.send(request).then(onCopySuccess, onError: onError);
252 : }
253 :
254 1 : return completer.future;
255 : }
256 :
257 : /// Specialised 'get' for change notifications
258 : Future<String> getString(String url) {
259 1 : final Completer completer = new Completer<String>();
260 :
261 : /* Must have authentication */
262 1 : final Map wiltHeaders = new Map<String, String>();
263 1 : wiltHeaders["Accept"] = "application/json";
264 1 : if (_user != null) {
265 1 : switch (_authType) {
266 1 : case Wilt.authBasic:
267 3 : final String authStringToEncode = "$_user:$_password";
268 : final String encodedAuthString =
269 2 : CryptoUtils.bytesToBase64(authStringToEncode.codeUnits);
270 1 : final String authString = "Basic $encodedAuthString";
271 1 : wiltHeaders['Authorization'] = authString;
272 : break;
273 :
274 0 : case Wilt.authNone:
275 : break;
276 : }
277 : }
278 :
279 3 : _client.get(url, headers: wiltHeaders).then((response) {
280 2 : completer.complete(response.body);
281 : });
282 :
283 1 : return completer.future;
284 : }
285 :
286 : /// Authentication parameters for change notification
287 : void notificationAuthParams(String user, String password, String authType) {
288 1 : _user = user;
289 1 : _password = password;
290 1 : _authType = authType;
291 : }
292 : }
|