globus_connect_gridftp_server  16.7
globus_i_dsi_rest.h
1 /*
2  * Copyright 1999-2016 University of Chicago
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
22 #ifndef GLOBUS_I_DSI_REST_H
23 #define GLOBUS_I_DSI_REST_H
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
29 #include "globus_i_gridftp_server_config.h"
30 #include <stdbool.h>
31 
32 #include "globus_dsi_rest.h"
33 #include "globus_common.h"
34 #include "globus_gridftp_server.h"
35 
36 #include <curl/curl.h>
37 #include <jansson.h>
38 
39 typedef
40 struct globus_i_dsi_rest_read_json_arg_s
41 {
42  size_t buffer_used;
43  size_t buffer_len;
44  char *buffer;
45  json_t **json_out;
46 }
47 globus_i_dsi_rest_read_json_arg_t;
48 
49 typedef struct
50 globus_i_dsi_rest_buffer_s
51 {
52  size_t buffer_len;
53  size_t buffer_used;
54  uint64_t transfer_offset;
55  struct globus_i_dsi_rest_buffer_s *next;
56  unsigned char buffer[];
57 }
58 globus_i_dsi_rest_buffer_t;
59 
60 typedef struct
61 globus_i_dsi_rest_idle_arg_s
62 {
63  globus_abstime_t last_activity;
64  uintptr_t idle_timeout;
65  uint64_t last_amt_read;
66  uint64_t last_amt_written;
67 }
68 globus_i_dsi_rest_idle_arg_t;
69 
70 typedef
71 struct globus_i_dsi_rest_gridftp_op_arg_s
72 {
73  globus_gfs_operation_t op;
74  globus_mutex_t mutex;
75  globus_cond_t cond;
76  globus_result_t result;
77 
78  uint64_t offset;
79  uint64_t end_offset;
80  // If we hit EOF or end of expected read
81  bool eof;
82  // Points to app's gridftp_op_arg's eof field, only set to true
83  // if we get an eof response from the GridFTP server.
84  bool *eofp;
85 
86  globus_i_dsi_rest_buffer_t *pending_buffers;
87  globus_i_dsi_rest_buffer_t **pending_buffers_last;
88 
89  globus_i_dsi_rest_buffer_t *current_buffer;
90 
91  globus_i_dsi_rest_buffer_t *registered_buffers;
92  int registered_buffers_count;
93 
94  globus_i_dsi_rest_buffer_t *free_buffers;
95 }
96 globus_i_dsi_rest_gridftp_op_arg_t;
97 
98 
99 typedef
100 struct globus_i_dsi_rest_write_multipart_arg_s
101 {
102  char *boundary;
103  size_t num_parts;
104  size_t part_index;
105  char *current_boundary;
106  size_t current_boundary_offset;
107  size_t current_boundary_length;
108  struct globus_i_dsi_rest_write_part_s
109  *parts;
110 }
111 globus_i_dsi_rest_write_multipart_arg_t;
112 
113 typedef
114 struct globus_i_dsi_rest_write_block_arg_s
115 {
117  void *block_data;
119  size_t block_len;
121  size_t offset;
122 }
123 globus_i_dsi_rest_write_block_arg_t;
124 
125 typedef
126 struct globus_i_dsi_rest_write_blocks_arg_s
127 {
128  size_t block_count;
129  size_t current_block;
130  globus_i_dsi_rest_write_block_arg_t*blocks;
131 }
132 globus_i_dsi_rest_write_blocks_arg_t;
133 
134 typedef
135 struct globus_i_dsi_rest_write_part_s
136 {
138  globus_dsi_rest_key_array_t malloced_headers;
139 
140  globus_dsi_rest_write_t data_write_callback;
141  void *data_write_callback_arg;
142 }
143 globus_i_dsi_rest_write_part_t;
144 
145 typedef
146 struct globus_i_dsi_rest_read_part_s
147 {
149 
150  globus_dsi_rest_response_t response_callback;
151  void *response_callback_arg;
152 
153  globus_dsi_rest_read_t data_read_callback;
154  void *data_read_callback_arg;
155 
156  globus_dsi_rest_read_t data_peek_callback;
157  void *data_peek_callback_arg;
158 }
159 globus_i_dsi_rest_read_part_t;
160 
161 typedef
162 struct globus_i_dsi_rest_read_multipart_arg_s
163 {
164  size_t num_parts;
165  size_t part_index;
166  globus_i_dsi_rest_read_part_t *parts;
167 
168  char *boundary;
169  size_t boundary_length;
170 
171  char *boundary_buffer;
172  size_t boundary_buffer_length;
173  size_t boundary_buffer_offset;
174 
175  size_t match_counter;
176 
177  bool need_header;
178  char *header_buffer;
179  size_t header_buffer_offset;
180 }
181 globus_i_dsi_rest_read_multipart_arg_t;
182 
186 typedef
187 struct globus_i_dsi_rest_request_s
188 {
189  CURL *handle;
190  globus_result_t result;
191  const char *method;
192  int response_code;
193  char response_reason[64];
194  struct curl_slist *request_headers;
195  char *complete_uri;
196 
197  off_t request_bytes_uploaded;
198  off_t response_bytes_downloaded;
199 
200  globus_i_dsi_rest_write_part_t write_part;
201  globus_i_dsi_rest_read_part_t read_part;
202 
203  globus_dsi_rest_response_t response_callback;
204  void *response_callback_arg;
205 
206  globus_dsi_rest_complete_t complete_callback;
207  void *complete_callback_arg;
208 
209  globus_dsi_rest_progress_t progress_callback;
210  void *progress_callback_arg;
211 
212  globus_i_dsi_rest_idle_arg_t idle_arg;
213 
214  uint64_t request_content_length;
215  bool request_content_length_set;
216 }
217 globus_i_dsi_rest_request_t;
218 
233 globus_result_t
234 globus_i_dsi_rest_handle_get(
235  CURL **handlep,
236  void *callback_arg);
237 
249 void
250 globus_i_dsi_rest_handle_release(
251  CURL *handle);
252 
253 
254 globus_result_t
255 globus_i_dsi_rest_compute_headers(
256  struct curl_slist **request_headers,
257  const globus_dsi_rest_key_array_t *headers);
258 
259 globus_result_t
260 globus_i_dsi_rest_set_request(
261  CURL *curl,
262  const char *method,
263  const char *uri,
264  struct curl_slist *headers,
265  const globus_dsi_rest_callbacks_t *callbacks);
266 
267 globus_result_t
268 globus_i_dsi_rest_add_header(
269  struct curl_slist **request_headers,
270  const char *header_name,
271  const char *header_value);
272 
273 globus_result_t
274 globus_i_dsi_rest_perform(
275  globus_i_dsi_rest_request_t *request);
276 
277 globus_result_t
278 globus_i_dsi_rest_encode_form_data(
279  const globus_dsi_rest_key_array_t *form_fields,
280  char **form_datap);
281 
282 globus_i_dsi_rest_buffer_t *
283 globus_i_dsi_rest_buffer_get(
284  globus_i_dsi_rest_gridftp_op_arg_t *gridftp_op_arg,
285  size_t size);
286 
287 void
288 globus_i_dsi_rest_uri_escape(
289  const char *raw,
290  char **encodedp,
291  size_t *availablep);
292 
293 globus_result_t
294 globus_i_dsi_rest_multipart_boundary_prepare(
295  const char *delimiter,
296  bool final,
297  globus_dsi_rest_key_array_t *part_header,
298  char **boundaryp,
299  size_t *boundary_lengthp);
300 
301 void
302 globus_i_dsi_rest_request_cleanup(
303  globus_i_dsi_rest_request_t *request);
304 
305 /* Callbacks that are passed to libcurl that cause user-specific callbacks */
306 int
307 globus_i_dsi_rest_xferinfo(
308  void *callback_arg,
309  curl_off_t dltotal,
310  curl_off_t dlnow,
311  curl_off_t ultotal,
312  curl_off_t ulnow);
313 
314 int
315 globus_i_dsi_rest_progress(
316  void *callback_arg,
317  double dltotal,
318  double dlnow,
319  double ultotal,
320  double ulnow);
321 
322 size_t
323 globus_i_dsi_rest_header(
324  char *buffer,
325  size_t size,
326  size_t nitems,
327  void *callback_arg);
328 
329 globus_result_t
330 globus_i_dsi_rest_header_parse(
332  char *buffer,
333  size_t size);
334 
335 size_t
336 globus_i_dsi_rest_write_data(
337  char *ptr,
338  size_t size,
339  size_t nmemb,
340  void *callback_arg);
341 
342 size_t
343 globus_i_dsi_rest_read_data(
344  char *buffer,
345  size_t size,
346  size_t nitems,
347  void *callback_arg);
348 
349 #define GlobusDsiRestErrorParameter() \
350  globus_error_put(GlobusDsiRestErrorParameterObject())
351 #define GlobusDsiRestErrorMemory() \
352  globus_error_put(GlobusDsiRestErrorMemoryObject())
353 #define GlobusDsiRestErrorParse(s) \
354  globus_error_put(GlobusDsiRestErrorParseObject(s))
355 #define GlobusDsiRestErrorCurl(rc) \
356  globus_error_put(GlobusDsiRestErrorCurlObject(rc))
357 #define GlobusDsiRestErrorJson(buffer, buffer_len, err) \
358  globus_error_put(GlobusDsiRestErrorJsonObject(buffer, buffer_len, err))
359 #define GlobusDsiRestErrorTimeOut() \
360  globus_error_put(GlobusDsiRestErrorTimeOutObject())
361 #define GlobusDsiRestErrorThreadFail(rc) \
362  globus_error_put(GlobusDsiRestErrorThreadFailObject(rc))
363 #define GlobusDsiRestErrorUnexpectedData(s, len) \
364  globus_error_put(GlobusDsiRestErrorUnexpectedDataObject(s, len))
365 
366 #define GlobusDsiRestErrorParameterObject() \
367  globus_error_construct_error( \
368  GLOBUS_DSI_REST_MODULE, \
369  NULL, \
370  GLOBUS_DSI_REST_ERROR_PARAMETER, \
371  __FILE__, \
372  __func__, \
373  __LINE__, \
374  "Invalid parameter")
375 #define GlobusDsiRestErrorMemoryObject() \
376  globus_error_construct_error( \
377  GLOBUS_DSI_REST_MODULE, \
378  NULL, \
379  GLOBUS_DSI_REST_ERROR_MEMORY, \
380  __FILE__, \
381  __func__, \
382  __LINE__, \
383  "Out of memory")
384 
385 #define GlobusDsiRestErrorParseObject(s) \
386  globus_error_construct_error( \
387  GLOBUS_DSI_REST_MODULE, \
388  NULL, \
389  GLOBUS_DSI_REST_ERROR_PARSE, \
390  __FILE__, \
391  __func__, \
392  __LINE__, \
393  "Unable to parse %s", s)
394 
395 #define GlobusDsiRestErrorCurlObject(rc) \
396  globus_error_construct_error( \
397  GLOBUS_DSI_REST_MODULE, \
398  NULL, \
399  GLOBUS_DSI_REST_ERROR_CURL, \
400  __FILE__, \
401  __func__, \
402  __LINE__, \
403  "libcurl error %d: %s", rc, curl_easy_strerror(rc))
404 #define GlobusDsiRestErrorJsonObject(buffer, buffer_len, err) \
405  globus_error_construct_error( \
406  GLOBUS_DSI_REST_MODULE, \
407  NULL, \
408  GLOBUS_DSI_REST_ERROR_JSON, \
409  __FILE__, \
410  __func__, \
411  __LINE__, \
412  "Error parsing \"%.*s\" as json: %s", \
413  (int) buffer_len, buffer, (err)->text)
414 #define GlobusDsiRestErrorTimeOutObject() \
415  globus_error_construct_error( \
416  GLOBUS_DSI_REST_MODULE, \
417  NULL, \
418  GLOBUS_DSI_REST_ERROR_TIME_OUT, \
419  __FILE__, \
420  __func__, \
421  __LINE__, \
422  "Operation timed out")
423 #define GlobusDsiRestErrorThreadFailObject(rc) \
424  globus_error_construct_error( \
425  GLOBUS_DSI_REST_MODULE, \
426  NULL, \
427  GLOBUS_DSI_REST_ERROR_THREAD_FAIL, \
428  __FILE__, \
429  __func__, \
430  __LINE__, \
431  "Thread create failed: %d", rc)
432 #define GlobusDsiRestErrorUnexpectedDataObject(s,len) \
433  globus_error_construct_error( \
434  GLOBUS_DSI_REST_MODULE, \
435  NULL, \
436  GLOBUS_DSI_REST_ERROR_UNEXPECTED_DATA, \
437  __FILE__, \
438  __func__, \
439  __LINE__, \
440  "Unexpected data failed: %.*s", (int)len, s)
441 
442 /* Logging */
443 GlobusDebugDeclare(GLOBUS_DSI_REST);
444 
445 enum
446 {
447  GLOBUS_DSI_REST_DATA = 1<<0,
448  GLOBUS_DSI_REST_TRACE = 1<<1,
449  GLOBUS_DSI_REST_INFO = 1<<2,
450  GLOBUS_DSI_REST_DEBUG = 1<<3,
451  GLOBUS_DSI_REST_WARN = 1<<4,
452  GLOBUS_DSI_REST_ERROR = 1<<5,
453 };
454 
455 extern const char * globus_i_dsi_rest_debug_level_names[];
456 
457 #define GlobusDsiRestLog(level, ...) \
458  do { \
459  int level__ = level; \
460  if (level__ > GLOBUS_DSI_REST_ERROR \
461  || level__ < 0 \
462  || globus_i_dsi_rest_debug_level_names[level__] == NULL) \
463  { \
464  level__ = 1; \
465  } \
466  if (GlobusDebugTrue(GLOBUS_DSI_REST, level__)) \
467  { \
468  flockfile(GlobusDebugMyFile(GLOBUS_DSI_REST)); \
469  GlobusDebugPrintf(GLOBUS_DSI_REST, level__, \
470  ("dsi_rest: %5s: %"PRIiMAX": %s: ", \
471  globus_i_dsi_rest_debug_level_names[level__], \
472  (intmax_t) getpid(), __func__)); \
473  GlobusDebugMyPrintf(GLOBUS_DSI_REST, \
474  (__VA_ARGS__)); \
475  funlockfile(GlobusDebugMyFile(GLOBUS_DSI_REST)); \
476  } \
477  } while (0)
478 
479 #define GlobusDsiRestData(...) GlobusDsiRestLog(GLOBUS_DSI_REST_DATA, __VA_ARGS__)
480 #define GlobusDsiRestTrace(...) GlobusDsiRestLog(GLOBUS_DSI_REST_TRACE, __VA_ARGS__)
481 #define GlobusDsiRestInfo(...) GlobusDsiRestLog(GLOBUS_DSI_REST_INFO, __VA_ARGS__)
482 #define GlobusDsiRestDebug(...) GlobusDsiRestLog(GLOBUS_DSI_REST_DEBUG, __VA_ARGS__)
483 #define GlobusDsiRestWarn(...) GlobusDsiRestLog(GLOBUS_DSI_REST_WARN, __VA_ARGS__)
484 #define GlobusDsiRestError(...) GlobusDsiRestLog(GLOBUS_DSI_REST_ERROR, __VA_ARGS__)
485 
486 #define GlobusDsiRestEnter() GlobusDsiRestTrace("enter\n")
487 #define GlobusDsiRestExit() GlobusDsiRestTrace("exit\n")
488 #define GlobusDsiRestExitResult(result) \
489  do { \
490  if (GlobusDebugTrue(GLOBUS_DSI_REST, GLOBUS_DSI_REST_TRACE)) \
491  { \
492  globus_object_t * obj = globus_error_peek(result); \
493  char *errstr = obj?globus_error_print_friendly(obj):strdup("Success"); \
494  GlobusDsiRestTrace("exit: %#x: %s\n", (unsigned) result, errstr?errstr:"UNKNOWN ERROR"); \
495  free(errstr); \
496  } \
497  } while (0)
498 #define GlobusDsiRestExitSizeT(size) GlobusDsiRestTrace("exit: %zu\n", size)
499 #define GlobusDsiRestExitInt(rc) GlobusDsiRestTrace("exit: %d\n", rc)
500 #define GlobusDsiRestExitBool(rc) GlobusDsiRestTrace("exit: %s\n", rc?"true":"false")
501 #define GlobusDsiRestExitPointer(p) GlobusDsiRestTrace("exit: %p\n", (void *)p)
502 
503 #define GlobusDsiRestLogResult(level, result) \
504  do { \
505  int __level = level; \
506  if (GlobusDebugTrue(GLOBUS_DSI_REST, (__level))) \
507  { \
508  globus_object_t * obj = globus_error_peek(result); \
509  char *errstr = obj?globus_error_print_friendly(obj):strdup("Success"); \
510  GlobusDsiRestLog(__level, "result=%#x message=%s\n", \
511  (unsigned int) result, \
512  errstr?errstr:"UNKNOWN ERROR"); \
513  free(errstr); \
514  } \
515  } while (0)
516 
517 extern globus_mutex_t globus_i_dsi_rest_handle_cache_mutex;
518 extern size_t globus_i_dsi_rest_handle_cache_index;
519 extern CURL *globus_i_dsi_rest_handle_cache[];
520 extern CURLSH *globus_i_dsi_rest_share;
521 
522 enum { GLOBUS_I_DSI_REST_HANDLE_CACHE_SIZE = 16 };
523 
524 #ifdef __cplusplus
525 }
526 #endif
527 
528 #endif /* GLOBUS_DSI_REST_H */
529 #endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */
globus_result_t(* globus_dsi_rest_read_t)(void *read_callback_arg, void *buffer, size_t buffer_length)
Data Read Callback Signature.
Definition: globus_dsi_rest.h:207
globus_result_t(* globus_dsi_rest_write_t)(void *write_callback_arg, void *buffer, size_t buffer_length, size_t *amount_copied)
Data Write Callback Signature.
Definition: globus_dsi_rest.h:168
globus_result_t(* globus_dsi_rest_progress_t)(void *progress_callback_arg, uint64_t total_read, uint64_t amt_read, uint64_t total_written, uint64_t amt_written)
Request Progress Callback Signature.
Definition: globus_dsi_rest.h:268
void(* globus_dsi_rest_complete_t)(void *complete_callback_arg, globus_result_t result)
Request Complete Callback Signature.
Definition: globus_dsi_rest.h:230
globus_result_t(* globus_dsi_rest_response_t)(void *response_callback_arg, int response_code, const char *response_status, const globus_dsi_rest_key_array_t *response_headers)
Response Callback Signature.
Definition: globus_dsi_rest.h:130
Key-Value Pair Array.
Definition: globus_dsi_rest.h:92