xref: /petsc/src/sys/webclient/globus.c (revision c6a7a37075f8bf8d34d92c4910d42445b7a3482d)
15dc0f0a4SBarry Smith #include <petscwebclient.h>
2bb04b57dSBarry Smith #pragma clang diagnostic ignored "-Wdeprecated-declarations"
345e40e47SBarry Smith #pragma gcc diagnostic   ignored "-Wdeprecated-declarations"
45dc0f0a4SBarry Smith 
55dc0f0a4SBarry Smith /*
65dc0f0a4SBarry Smith     Encodes and decodes from MIME Base64
75dc0f0a4SBarry Smith */
89371c9d4SSatish Balay static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
99371c9d4SSatish Balay                                 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
105dc0f0a4SBarry Smith 
11d71ae5a4SJacob Faibussowitsch static PetscErrorCode base64_encode(const unsigned char *data, unsigned char *encoded_data, size_t len)
12d71ae5a4SJacob Faibussowitsch {
13f5b927afSBarry Smith   static size_t mod_table[] = {0, 2, 1};
14f5b927afSBarry Smith   size_t        i, j;
155dc0f0a4SBarry Smith   size_t        input_length, output_length;
165dc0f0a4SBarry Smith 
175dc0f0a4SBarry Smith   PetscFunctionBegin;
189566063dSJacob Faibussowitsch   PetscCall(PetscStrlen((const char *)data, &input_length));
195dc0f0a4SBarry Smith   output_length = 4 * ((input_length + 2) / 3);
2008401ef6SPierre Jolivet   PetscCheck(output_length <= len, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Output length not large enough");
215dc0f0a4SBarry Smith 
225dc0f0a4SBarry Smith   for (i = 0, j = 0; i < input_length;) {
235dc0f0a4SBarry Smith     uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
245dc0f0a4SBarry Smith     uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
255dc0f0a4SBarry Smith     uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
265dc0f0a4SBarry Smith     uint32_t triple  = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
275dc0f0a4SBarry Smith 
285dc0f0a4SBarry Smith     encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
295dc0f0a4SBarry Smith     encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
305dc0f0a4SBarry Smith     encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
315dc0f0a4SBarry Smith     encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
325dc0f0a4SBarry Smith   }
335dc0f0a4SBarry Smith   encoded_data[j] = 0;
345dc0f0a4SBarry Smith   for (i = 0; i < mod_table[input_length % 3]; i++) encoded_data[output_length - 1 - i] = '=';
353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
365dc0f0a4SBarry Smith }
375dc0f0a4SBarry Smith 
38d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static PetscErrorCode base64_decode(const unsigned char *data, unsigned char *decoded_data, size_t length)
39d71ae5a4SJacob Faibussowitsch {
405dc0f0a4SBarry Smith   static char decoding_table[257];
415dc0f0a4SBarry Smith   static int  decode_table_built = 0;
42c1f4622dSBarry Smith   size_t      i, j;
435dc0f0a4SBarry Smith   size_t      input_length, output_length;
445dc0f0a4SBarry Smith 
455dc0f0a4SBarry Smith   PetscFunctionBegin;
465dc0f0a4SBarry Smith   if (!decode_table_built) {
475dc0f0a4SBarry Smith     for (i = 0; i < 64; i++) decoding_table[(unsigned char)encoding_table[i]] = i;
485dc0f0a4SBarry Smith     decode_table_built = 1;
495dc0f0a4SBarry Smith   }
505dc0f0a4SBarry Smith 
519566063dSJacob Faibussowitsch   PetscCall(PetscStrlen((const char *)data, &input_length));
5208401ef6SPierre Jolivet   PetscCheck(input_length % 4 == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input length must be divisible by 4");
535dc0f0a4SBarry Smith 
545dc0f0a4SBarry Smith   output_length = input_length / 4 * 3;
555dc0f0a4SBarry Smith   if (data[input_length - 1] == '=') (output_length)--;
565dc0f0a4SBarry Smith   if (data[input_length - 2] == '=') (output_length)--;
5708401ef6SPierre Jolivet   PetscCheck(output_length <= length, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Output length too shore");
585dc0f0a4SBarry Smith 
595dc0f0a4SBarry Smith   for (i = 0, j = 0; i < input_length;) {
605dc0f0a4SBarry Smith     uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
615dc0f0a4SBarry Smith     uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
625dc0f0a4SBarry Smith     uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
635dc0f0a4SBarry Smith     uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
645dc0f0a4SBarry Smith     uint32_t triple   = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6);
655dc0f0a4SBarry Smith 
665dc0f0a4SBarry Smith     if (j < output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
675dc0f0a4SBarry Smith     if (j < output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
685dc0f0a4SBarry Smith     if (j < output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
695dc0f0a4SBarry Smith   }
705dc0f0a4SBarry Smith   decoded_data[j] = 0;
713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
725dc0f0a4SBarry Smith }
735dc0f0a4SBarry Smith 
745dc0f0a4SBarry Smith #if defined(PETSC_HAVE_UNISTD_H)
755dc0f0a4SBarry Smith   #include <unistd.h>
765dc0f0a4SBarry Smith #endif
775dc0f0a4SBarry Smith 
785dc0f0a4SBarry Smith /*@C
795dc0f0a4SBarry Smith      PetscGlobusAuthorize - Get an access token allowing PETSc applications to make Globus file transfer requests
805dc0f0a4SBarry Smith 
81811af0c4SBarry Smith    Not collective, only the first process in `MPI_Comm` does anything
825dc0f0a4SBarry Smith 
835dc0f0a4SBarry Smith    Input Parameters:
845dc0f0a4SBarry Smith +  comm - the MPI communicator
855dc0f0a4SBarry Smith -  tokensize - size of the token array
865dc0f0a4SBarry Smith 
875dc0f0a4SBarry Smith    Output Parameters:
88811af0c4SBarry Smith .  access_token - can be used with `PetscGlobusUpLoad()` for 30 days
895dc0f0a4SBarry Smith 
9095452b02SPatrick Sanan    Notes:
9195452b02SPatrick Sanan     This call requires stdout and stdin access from process 0 on the MPI communicator
925dc0f0a4SBarry Smith 
93c4762a1bSJed Brown    You can run src/sys/webclient/tutorials/globusobtainaccesstoken to get an access token
945dc0f0a4SBarry Smith 
952b26979fSBarry Smith    Level: intermediate
962b26979fSBarry Smith 
97db781477SPatrick Sanan .seealso: `PetscGoogleDriveRefresh()`, `PetscGoogleDriveUpload()`, `PetscURLShorten()`, `PetscGlobusUpload()`
985dc0f0a4SBarry Smith @*/
99d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGlobusAuthorize(MPI_Comm comm, char access_token[], size_t tokensize)
100d71ae5a4SJacob Faibussowitsch {
1015dc0f0a4SBarry Smith   SSL_CTX    *ctx;
1025dc0f0a4SBarry Smith   SSL        *ssl;
1035dc0f0a4SBarry Smith   int         sock;
1045dc0f0a4SBarry Smith   char        buff[8 * 1024], *ptr, head[1024];
1055dc0f0a4SBarry Smith   PetscMPIInt rank;
1065dc0f0a4SBarry Smith   size_t      len;
1075dc0f0a4SBarry Smith   PetscBool   found;
1085dc0f0a4SBarry Smith 
1095dc0f0a4SBarry Smith   PetscFunctionBegin;
1109566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
111dd400576SPatrick Sanan   if (rank == 0) {
112cc73adaaSBarry Smith     PetscCheck(isatty(fileno(PETSC_STDOUT)), PETSC_COMM_SELF, PETSC_ERR_USER, "Requires users input/output");
1139566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Enter globus username:"));
1145dc0f0a4SBarry Smith     ptr = fgets(buff, 1024, stdin);
11528b400f6SJacob Faibussowitsch     PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno);
1169566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(buff, &len));
1175dc0f0a4SBarry Smith     buff[len - 1] = ':'; /* remove carriage return at end of line */
1185dc0f0a4SBarry Smith 
1199566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Enter globus password:"));
1205dc0f0a4SBarry Smith     ptr = fgets(buff + len, 1024 - len, stdin);
12128b400f6SJacob Faibussowitsch     PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno);
1229566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(buff, &len));
1235dc0f0a4SBarry Smith     buff[len - 1] = '\0'; /* remove carriage return at end of line */
124*c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(head, "Authorization: Basic ", sizeof(head)));
1259566063dSJacob Faibussowitsch     PetscCall(base64_encode((const unsigned char *)buff, (unsigned char *)(head + 21), sizeof(head) - 21));
126*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(head, "\r\n", sizeof(head)));
1275dc0f0a4SBarry Smith 
1289566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
1299566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("nexus.api.globusonline.org", 443, ctx, &sock, &ssl));
1309566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("GET", "nexus.api.globusonline.org/goauth/token?grant_type=client_credentials", head, "application/x-www-form-urlencoded", NULL, ssl, buff, sizeof(buff)));
1319566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
1325dc0f0a4SBarry Smith     close(sock);
1335dc0f0a4SBarry Smith 
1349566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "access_token", access_token, tokensize, &found));
13528b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Globus did not return access token");
1365dc0f0a4SBarry Smith 
1379566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Here is your Globus access token, save it in a save place, in the future you can run PETSc\n"));
1389566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "programs with the option -globus_access_token %s\n", access_token));
1399566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "to access Globus automatically\n"));
1405dc0f0a4SBarry Smith   }
1413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1425dc0f0a4SBarry Smith }
1435dc0f0a4SBarry Smith 
1445dc0f0a4SBarry Smith /*@C
1455dc0f0a4SBarry Smith      PetscGlobusGetTransfers - Get a record of current transfers requested from Globus
1465dc0f0a4SBarry Smith 
147811af0c4SBarry Smith    Not collective, only the first process in `MPI_Comm` does anything
1485dc0f0a4SBarry Smith 
1495dc0f0a4SBarry Smith    Input Parameters:
1505dc0f0a4SBarry Smith +  comm - the MPI communicator
1515dc0f0a4SBarry Smith .  access_token - Globus access token, if NULL will check in options database for -globus_access_token XXX otherwise
152811af0c4SBarry Smith                   will call `PetscGlobusAuthorize()`.
1535dc0f0a4SBarry Smith -  buffsize - size of the buffer
1545dc0f0a4SBarry Smith 
1555dc0f0a4SBarry Smith    Output Parameters:
1565dc0f0a4SBarry Smith .  buff - location to put Globus information
1575dc0f0a4SBarry Smith 
1582b26979fSBarry Smith    Level: intermediate
1592b26979fSBarry Smith 
160db781477SPatrick Sanan .seealso: `PetscGoogleDriveRefresh()`, `PetscGoogleDriveUpload()`, `PetscURLShorten()`, `PetscGlobusUpload()`, `PetscGlobusAuthorize()`
1615dc0f0a4SBarry Smith @*/
162d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGlobusGetTransfers(MPI_Comm comm, const char access_token[], char buff[], size_t buffsize)
163d71ae5a4SJacob Faibussowitsch {
1645dc0f0a4SBarry Smith   SSL_CTX    *ctx;
1655dc0f0a4SBarry Smith   SSL        *ssl;
1665dc0f0a4SBarry Smith   int         sock;
1675dc0f0a4SBarry Smith   char        head[4096];
1685dc0f0a4SBarry Smith   PetscMPIInt rank;
1695dc0f0a4SBarry Smith 
1705dc0f0a4SBarry Smith   PetscFunctionBegin;
1719566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
172dd400576SPatrick Sanan   if (rank == 0) {
173*c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(head, "Authorization : Globus-Goauthtoken ", sizeof(head)));
1745dc0f0a4SBarry Smith     if (access_token) {
175*c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(head, access_token, sizeof(head)));
1765dc0f0a4SBarry Smith     } else {
1775dc0f0a4SBarry Smith       PetscBool set;
1785dc0f0a4SBarry Smith       char      accesstoken[4096];
1799566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetString(NULL, NULL, "-globus_access_token", accesstoken, sizeof(accesstoken), &set));
18028b400f6SJacob Faibussowitsch       PetscCheck(set, PETSC_COMM_SELF, PETSC_ERR_USER, "Pass in Globus accesstoken or use -globus_access_token XXX");
181*c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(head, accesstoken, sizeof(head)));
1825dc0f0a4SBarry Smith     }
183*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(head, "\r\n", sizeof(head)));
1845dc0f0a4SBarry Smith 
1859566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
1869566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("transfer.api.globusonline.org", 443, ctx, &sock, &ssl));
1879566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("GET", "transfer.api.globusonline.org/v0.10/tasksummary", head, "application/json", NULL, ssl, buff, buffsize));
1889566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
1895dc0f0a4SBarry Smith     close(sock);
1905dc0f0a4SBarry Smith   }
1913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1925dc0f0a4SBarry Smith }
1935dc0f0a4SBarry Smith 
1945dc0f0a4SBarry Smith /*@C
1955dc0f0a4SBarry Smith      PetscGlobusUpload - Loads a file to Globus
1965dc0f0a4SBarry Smith 
197811af0c4SBarry Smith      Not collective, only the first process in the `MPI_Comm` uploads the file
1985dc0f0a4SBarry Smith 
1995dc0f0a4SBarry Smith   Input Parameters:
2005dc0f0a4SBarry Smith +   comm - MPI communicator
201811af0c4SBarry Smith .   access_token - obtained with `PetscGlobusAuthorize()`, pass NULL to use -globus_access_token XXX from the PETSc database
2025dc0f0a4SBarry Smith -   filename - file to upload
2035dc0f0a4SBarry Smith 
204811af0c4SBarry Smith   Options Database Key:
20510699b91SBarry Smith .  -globus_access_token XXX - the Globus token
2065dc0f0a4SBarry Smith 
2072b26979fSBarry Smith    Level: intermediate
2082b26979fSBarry Smith 
209db781477SPatrick Sanan .seealso: `PetscURLShorten()`, `PetscGoogleDriveAuthorize()`, `PetscGoogleDriveRefresh()`, `PetscGlobusAuthorize()`
2105dc0f0a4SBarry Smith @*/
211d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGlobusUpload(MPI_Comm comm, const char access_token[], const char filename[])
212d71ae5a4SJacob Faibussowitsch {
2135dc0f0a4SBarry Smith   SSL_CTX    *ctx;
2145dc0f0a4SBarry Smith   SSL        *ssl;
2155dc0f0a4SBarry Smith   int         sock;
2165dc0f0a4SBarry Smith   char        head[4096], buff[8 * 1024], body[4096], submission_id[4096];
2175dc0f0a4SBarry Smith   PetscMPIInt rank;
2185dc0f0a4SBarry Smith   PetscBool   flg, found;
2195dc0f0a4SBarry Smith 
2205dc0f0a4SBarry Smith   PetscFunctionBegin;
2219566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
222dd400576SPatrick Sanan   if (rank == 0) {
2239566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(filename, 'r', &flg));
22428b400f6SJacob Faibussowitsch     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to find file: %s", filename);
2255dc0f0a4SBarry Smith 
226*c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(head, "Authorization : Globus-Goauthtoken ", sizeof(head)));
2275dc0f0a4SBarry Smith     if (access_token) {
228*c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(head, access_token, sizeof(head)));
2295dc0f0a4SBarry Smith     } else {
2305dc0f0a4SBarry Smith       PetscBool set;
2315dc0f0a4SBarry Smith       char      accesstoken[4096];
2329566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetString(NULL, NULL, "-globus_access_token", accesstoken, sizeof(accesstoken), &set));
23328b400f6SJacob Faibussowitsch       PetscCheck(set, PETSC_COMM_SELF, PETSC_ERR_USER, "Pass in Globus accesstoken or use -globus_access_token XXX");
234*c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(head, accesstoken, sizeof(head)));
2355dc0f0a4SBarry Smith     }
236*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(head, "\r\n", sizeof(head)));
2375dc0f0a4SBarry Smith 
2385dc0f0a4SBarry Smith     /* Get Globus submission id */
2399566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
2409566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("transfer.api.globusonline.org", 443, ctx, &sock, &ssl));
2419566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("GET", "transfer.api.globusonline.org/v0.10/submission_id", head, "application/json", NULL, ssl, buff, sizeof(buff)));
2429566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
2435dc0f0a4SBarry Smith     close(sock);
2449566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "value", submission_id, sizeof(submission_id), &found));
24528b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Globus did not return submission id");
2465dc0f0a4SBarry Smith 
2475dc0f0a4SBarry Smith     /* build JSON body of transfer request */
248*c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(body, "{", sizeof(body)));
2499371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "submission_id", submission_id, sizeof(body)));
250*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2519371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "DATA_TYPE", "transfer", sizeof(body)));
252*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2539371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "sync_level", "null", sizeof(body)));
254*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2559371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "source_endpoint", "barryfsmith#MacBookPro", sizeof(body)));
256*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2579371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "label", "PETSc transfer label", sizeof(body)));
258*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2599371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "length", "1", sizeof(body)));
260*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2619371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "destination_endpoint", "mcs#home", sizeof(body)));
262*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2635dc0f0a4SBarry Smith 
264*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "\"DATA\": [ {", sizeof(body)));
2659371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "source_path", "/~/FEM_GPU.pdf", sizeof(body)));
266*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2679371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "destination_path", "/~/FEM_GPU.pdf", sizeof(body)));
268*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2699371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "verify_size", "null", sizeof(body)));
270*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2719371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "recursive", "false", sizeof(body)));
272*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2739566063dSJacob Faibussowitsch     PetscCall(PetscPushJSONValue(body, "DATA_TYPE", "transfer_item", sizeof(body)));
274*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "} ] }", sizeof(body)));
2755dc0f0a4SBarry Smith 
2769566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
2779566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("transfer.api.globusonline.org", 443, ctx, &sock, &ssl));
2789566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("POST", "transfer.api.globusonline.org/v0.10/transfer", head, "application/json", body, ssl, buff, sizeof(buff)));
2799566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
2805dc0f0a4SBarry Smith     close(sock);
2819566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "code", submission_id, sizeof(submission_id), &found));
28228b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Globus did not return code on transfer");
2839566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(submission_id, "Accepted", &found));
28428b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Globus did not accept transfer");
2855dc0f0a4SBarry Smith   }
2863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2875dc0f0a4SBarry Smith }
288