xref: /petsc/src/sys/webclient/box.c (revision c6a7a37075f8bf8d34d92c4910d42445b7a3482d)
14a285bdaSBarry Smith 
24a285bdaSBarry Smith #include <petscwebclient.h>
3bb04b57dSBarry Smith #pragma clang diagnostic ignored "-Wdeprecated-declarations"
445e40e47SBarry Smith #pragma gcc diagnostic   ignored "-Wdeprecated-declarations"
54a285bdaSBarry Smith 
64a285bdaSBarry Smith /*
74a285bdaSBarry Smith    These variables identify the code as a PETSc application to Box.
84a285bdaSBarry Smith 
9a8d69d7bSBarry Smith    See -   https://stackoverflow.com/questions/4616553/using-oauth-in-free-open-source-software
10a8d69d7bSBarry Smith    Users can get their own application IDs - goto https://developer.box.com
114a285bdaSBarry Smith 
124a285bdaSBarry Smith */
134a285bdaSBarry Smith #define PETSC_BOX_CLIENT_ID "sse42nygt4zqgrdwi0luv79q1u1f0xza"
144a285bdaSBarry Smith #define PETSC_BOX_CLIENT_ST "A0Dy4KgOYLB2JIYZqpbze4EzjeIiX5k4"
154a285bdaSBarry Smith 
16f044a08eSBarry Smith #if defined(PETSC_HAVE_SAWS)
174a285bdaSBarry Smith   #include <mongoose.h>
184a285bdaSBarry Smith 
194a285bdaSBarry Smith static volatile char *result = NULL;
204a285bdaSBarry Smith 
21d71ae5a4SJacob Faibussowitsch static int PetscBoxWebServer_Private(struct mg_connection *conn)
22d71ae5a4SJacob Faibussowitsch {
234a285bdaSBarry Smith   const struct mg_request_info *request_info = mg_get_request_info(conn);
244a285bdaSBarry Smith   result                                     = (char *)request_info->query_string;
25f044a08eSBarry Smith   return 1; /* Mongoose will now not handle the request */
264a285bdaSBarry Smith }
274a285bdaSBarry Smith 
28f044a08eSBarry Smith /*
29f044a08eSBarry Smith     Box can only return an authorization code to a Webserver, hence we need to start one up and wait for
30f044a08eSBarry Smith     the authorization code to arrive from Box
31f044a08eSBarry Smith */
32d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscBoxStartWebServer_Private(void)
33d71ae5a4SJacob Faibussowitsch {
344a285bdaSBarry Smith   int                 optionsLen = 5;
354a285bdaSBarry Smith   const char         *options[optionsLen];
364a285bdaSBarry Smith   struct mg_callbacks callbacks;
374a285bdaSBarry Smith   struct mg_context  *ctx;
3868e69593SBarry Smith   char                keyfile[PETSC_MAX_PATH_LEN];
3968e69593SBarry Smith   PetscBool           exists;
404a285bdaSBarry Smith 
414a285bdaSBarry Smith   PetscFunctionBegin;
424a285bdaSBarry Smith   options[0] = "listening_ports";
434a285bdaSBarry Smith   options[1] = "8081s";
4468e69593SBarry Smith 
45*c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(keyfile, "sslclient.pem", sizeof(keyfile)));
469566063dSJacob Faibussowitsch   PetscCall(PetscTestFile(keyfile, 'r', &exists));
4768e69593SBarry Smith   if (!exists) {
489566063dSJacob Faibussowitsch     PetscCall(PetscGetHomeDirectory(keyfile, PETSC_MAX_PATH_LEN));
49*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(keyfile, "/", sizeof(keyfile)));
50*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(keyfile, "sslclient.pem", sizeof(keyfile)));
519566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(keyfile, 'r', &exists));
5228b400f6SJacob Faibussowitsch     PetscCheck(exists, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate sslclient.pem file in current directory or home directory");
5368e69593SBarry Smith   }
5468e69593SBarry Smith 
554a285bdaSBarry Smith   options[2] = "ssl_certificate";
5668e69593SBarry Smith   options[3] = keyfile;
574a285bdaSBarry Smith   options[4] = NULL;
584a285bdaSBarry Smith 
594a285bdaSBarry Smith   /* Prepare callbacks structure. We have only one callback, the rest are NULL. */
609566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(&callbacks, sizeof(callbacks)));
614a285bdaSBarry Smith   callbacks.begin_request = PetscBoxWebServer_Private;
624a285bdaSBarry Smith   ctx                     = mg_start(&callbacks, NULL, options);
6328b400f6SJacob Faibussowitsch   PetscCheck(ctx, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to start up webserver");
644a285bdaSBarry Smith   while (!result) { };
653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
664a285bdaSBarry Smith }
674a285bdaSBarry Smith 
6868e69593SBarry Smith   #if defined(PETSC_HAVE_UNISTD_H)
6968e69593SBarry Smith     #include <unistd.h>
7068e69593SBarry Smith   #endif
7168e69593SBarry Smith 
724a285bdaSBarry Smith /*@C
734a285bdaSBarry Smith      PetscBoxAuthorize - Get authorization and refresh token for accessing Box drive from PETSc
744a285bdaSBarry Smith 
75811af0c4SBarry Smith    Not collective, only the first rank in `MPI_Comm` does anything
764a285bdaSBarry Smith 
774a285bdaSBarry Smith    Input Parameters:
784a285bdaSBarry Smith +  comm - the MPI communicator
794a285bdaSBarry Smith -  tokensize - size of the token arrays
804a285bdaSBarry Smith 
814a285bdaSBarry Smith    Output Parameters:
82811af0c4SBarry Smith +  access_token - can be used with `PetscBoxUpload()` for this one session
83811af0c4SBarry Smith -  refresh_token - can be used for ever to obtain new access_tokens with `PetscBoxRefresh()`, guard this like a password
844a285bdaSBarry Smith                    it gives access to your Box Drive
854a285bdaSBarry Smith 
8695452b02SPatrick Sanan    Notes:
8795452b02SPatrick Sanan     This call requires stdout and stdin access from process 0 on the MPI communicator
884a285bdaSBarry Smith 
89c4762a1bSJed Brown    You can run src/sys/webclient/tutorials/boxobtainrefreshtoken to get a refresh token and then in the future pass it to
904a285bdaSBarry Smith    PETSc programs with -box_refresh_token XXX
914a285bdaSBarry Smith 
92f044a08eSBarry Smith    This requires PETSc be installed using --with-saws or --download-saws
93f044a08eSBarry Smith 
9468e69593SBarry Smith    Requires the user have created a self-signed ssl certificate with
9568e69593SBarry Smith 
9668e69593SBarry Smith $    saws/CA.pl  -newcert  (using the passphrase of password)
9768e69593SBarry Smith $    cat newkey.pem newcert.pem > sslclient.pem
9868e69593SBarry Smith 
9968e69593SBarry Smith     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
10068e69593SBarry Smith     silly but it was all I could figure out.
10168e69593SBarry Smith 
1022b26979fSBarry Smith    Level: intermediate
1032b26979fSBarry Smith 
104db781477SPatrick Sanan .seealso: `PetscBoxRefresh()`, `PetscBoxUpload()`, `PetscURLShorten()`
1054a285bdaSBarry Smith @*/
106d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscBoxAuthorize(MPI_Comm comm, char access_token[], char refresh_token[], size_t tokensize)
107d71ae5a4SJacob Faibussowitsch {
1084a285bdaSBarry Smith   SSL_CTX    *ctx;
1094a285bdaSBarry Smith   SSL        *ssl;
1104a285bdaSBarry Smith   int         sock;
1115dc0f0a4SBarry Smith   char        buff[8 * 1024], body[1024];
1124a285bdaSBarry Smith   PetscMPIInt rank;
1135dc0f0a4SBarry Smith   PetscBool   flg, found;
1144a285bdaSBarry Smith 
1154a285bdaSBarry Smith   PetscFunctionBegin;
1169566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
117dd400576SPatrick Sanan   if (rank == 0) {
118cc73adaaSBarry Smith     PetscCheck(isatty(fileno(PETSC_STDOUT)), PETSC_COMM_SELF, PETSC_ERR_USER, "Requires users input/output");
119d0609cedSBarry Smith     PetscCall(PetscPrintf(comm, "Cut and paste the following into your browser:\n\n"
1204a285bdaSBarry Smith                                 "https://www.box.com/api/oauth2/authorize?"
1214a285bdaSBarry Smith                                 "response_type=code&"
1229371c9d4SSatish Balay                                 "client_id=" PETSC_BOX_CLIENT_ID "&state=PETScState"
123d0609cedSBarry Smith                                 "\n\n"));
1249566063dSJacob Faibussowitsch     PetscCall(PetscBoxStartWebServer_Private());
1259566063dSJacob Faibussowitsch     PetscCall(PetscStrbeginswith((const char *)result, "state=PETScState&code=", &flg));
12628b400f6SJacob Faibussowitsch     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_LIB, "Did not get expected string from Box got %s", result);
1279566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(buff, (const char *)result + 22, sizeof(buff)));
1284a285bdaSBarry Smith 
1299566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
1309566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("www.box.com", 443, ctx, &sock, &ssl));
131*c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(body, "code=", sizeof(body)));
132*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, buff, sizeof(body)));
133*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "&client_id=", sizeof(body)));
134*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, PETSC_BOX_CLIENT_ID, sizeof(body)));
135*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "&client_secret=", sizeof(body)));
136*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, PETSC_BOX_CLIENT_ST, sizeof(body)));
137*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "&grant_type=authorization_code", sizeof(body)));
1384a285bdaSBarry Smith 
1399566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("POST", "www.box.com/api/oauth2/token", NULL, "application/x-www-form-urlencoded", body, ssl, buff, sizeof(buff)));
1409566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
1414a285bdaSBarry Smith     close(sock);
1424a285bdaSBarry Smith 
1439566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "access_token", access_token, tokensize, &found));
14428b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return access token");
1459566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "refresh_token", refresh_token, tokensize, &found));
14628b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return refresh token");
1474a285bdaSBarry Smith 
1489566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Here is your Box refresh token, save it in a save place, in the future you can run PETSc\n"));
1499566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "programs with the option -box_refresh_token %s\n", refresh_token));
1509566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "to access Box Drive automatically\n"));
1514a285bdaSBarry Smith   }
1523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1534a285bdaSBarry Smith }
154f044a08eSBarry Smith #endif
1554a285bdaSBarry Smith 
1564a285bdaSBarry Smith /*@C
1574a285bdaSBarry Smith      PetscBoxRefresh - Get a new authorization token for accessing Box drive from PETSc from a refresh token
1584a285bdaSBarry Smith 
159811af0c4SBarry Smith    Not collective, only the first process in the `MPI_Comm` does anything
1604a285bdaSBarry Smith 
1614a285bdaSBarry Smith    Input Parameters:
1624a285bdaSBarry Smith +   comm - MPI communicator
163811af0c4SBarry Smith .   refresh token - obtained with `PetscBoxAuthorize()`, if NULL PETSc will first look for one in the options data
164811af0c4SBarry Smith                     if not found it will call `PetscBoxAuthorize()`
1654a285bdaSBarry Smith -   tokensize - size of the output string access_token
1664a285bdaSBarry Smith 
167d8d19677SJose E. Roman    Output Parameters:
168811af0c4SBarry Smith +   access_token - token that can be passed to `PetscBoxUpload()`
1694a285bdaSBarry Smith -   new_refresh_token - the old refresh token is no longer valid, not this is different than Google where the same refresh_token is used forever
1704a285bdaSBarry Smith 
1712b26979fSBarry Smith    Level: intermediate
1722b26979fSBarry Smith 
173db781477SPatrick Sanan .seealso: `PetscURLShorten()`, `PetscBoxAuthorize()`, `PetscBoxUpload()`
1744a285bdaSBarry Smith @*/
175d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscBoxRefresh(MPI_Comm comm, const char refresh_token[], char access_token[], char new_refresh_token[], size_t tokensize)
176d71ae5a4SJacob Faibussowitsch {
1774a285bdaSBarry Smith   SSL_CTX    *ctx;
1784a285bdaSBarry Smith   SSL        *ssl;
1794a285bdaSBarry Smith   int         sock;
1805dc0f0a4SBarry Smith   char        buff[8 * 1024], body[1024];
1814a285bdaSBarry Smith   PetscMPIInt rank;
1825dc0f0a4SBarry Smith   char       *refreshtoken = (char *)refresh_token;
1835dc0f0a4SBarry Smith   PetscBool   found;
1844a285bdaSBarry Smith 
1854a285bdaSBarry Smith   PetscFunctionBegin;
1869566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
187dd400576SPatrick Sanan   if (rank == 0) {
1884a285bdaSBarry Smith     if (!refresh_token) {
1894a285bdaSBarry Smith       PetscBool set;
1909566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(512, &refreshtoken));
1919566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetString(NULL, NULL, "-box_refresh_token", refreshtoken, sizeof(refreshtoken), &set));
19299374591SBarry Smith #if defined(PETSC_HAVE_SAWS)
1934a285bdaSBarry Smith       if (!set) {
1949566063dSJacob Faibussowitsch         PetscCall(PetscBoxAuthorize(comm, access_token, new_refresh_token, 512 * sizeof(char)));
1959566063dSJacob Faibussowitsch         PetscCall(PetscFree(refreshtoken));
1963ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
1974a285bdaSBarry Smith       }
19899374591SBarry Smith #else
19928b400f6SJacob Faibussowitsch       PetscCheck(set, PETSC_COMM_SELF, PETSC_ERR_LIB, "Must provide refresh token with -box_refresh_token XXX");
20099374591SBarry Smith #endif
2014a285bdaSBarry Smith     }
2029566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
2039566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("www.box.com", 443, ctx, &sock, &ssl));
204*c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(body, "client_id=", sizeof(body)));
205*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, PETSC_BOX_CLIENT_ID, sizeof(body)));
206*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "&client_secret=", sizeof(body)));
207*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, PETSC_BOX_CLIENT_ST, sizeof(body)));
208*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "&refresh_token=", sizeof(body)));
209*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, refreshtoken, sizeof(body)));
2109566063dSJacob Faibussowitsch     if (!refresh_token) PetscCall(PetscFree(refreshtoken));
211*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "&grant_type=refresh_token", sizeof(body)));
2124a285bdaSBarry Smith 
2139566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("POST", "www.box.com/api/oauth2/token", NULL, "application/x-www-form-urlencoded", body, ssl, buff, sizeof(buff)));
2149566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
2154a285bdaSBarry Smith     close(sock);
2164a285bdaSBarry Smith 
2179566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "access_token", access_token, tokensize, &found));
21828b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return access token");
2199566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "refresh_token", new_refresh_token, tokensize, &found));
22028b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return refresh token");
22193e1d32fSBarry Smith 
2229566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Here is your new Box refresh token, save it in a save place, in the future you can run PETSc\n"));
2239566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "programs with the option -box_refresh_token %s\n", new_refresh_token));
2249566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "to access Box Drive automatically\n"));
2254a285bdaSBarry Smith   }
2263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2274a285bdaSBarry Smith }
2284a285bdaSBarry Smith 
2294a285bdaSBarry Smith #include <sys/stat.h>
2304a285bdaSBarry Smith 
2314a285bdaSBarry Smith /*@C
2324a285bdaSBarry Smith      PetscBoxUpload - Loads a file to the Box Drive
2334a285bdaSBarry Smith 
23493e1d32fSBarry Smith      This routine has not yet been written; it is just copied from Google Drive
23593e1d32fSBarry Smith 
236811af0c4SBarry Smith      Not collective, only the first process in the `MPI_Comm` uploads the file
2374a285bdaSBarry Smith 
2384a285bdaSBarry Smith   Input Parameters:
2394a285bdaSBarry Smith +   comm - MPI communicator
240811af0c4SBarry Smith .   access_token - obtained with `PetscBoxRefresh()`, pass NULL to have PETSc generate one
2414a285bdaSBarry Smith -   filename - file to upload; if you upload multiple times it will have different names each time on Box Drive
2424a285bdaSBarry Smith 
243811af0c4SBarry Smith   Options Database Key:
24410699b91SBarry Smith .  -box_refresh_token XXX - the token value
2454a285bdaSBarry Smith 
2464a285bdaSBarry Smith   Usage Patterns:
247811af0c4SBarry Smith .vb
2484a285bdaSBarry Smith     With PETSc option -box_refresh_token XXX given
2494a285bdaSBarry Smith     PetscBoxUpload(comm,NULL,filename);        will upload file with no user interaction
2504a285bdaSBarry Smith 
2514a285bdaSBarry Smith     Without PETSc option -box_refresh_token XXX given
2524a285bdaSBarry Smith     PetscBoxUpload(comm,NULL,filename);        for first use will prompt user to authorize access to Box Drive with their processor
2534a285bdaSBarry Smith 
2544a285bdaSBarry Smith     With PETSc option -box_refresh_token  XXX given
2554a285bdaSBarry Smith     PetscBoxRefresh(comm,NULL,access_token,sizeof(access_token));
2564a285bdaSBarry Smith     PetscBoxUpload(comm,access_token,filename);
2574a285bdaSBarry Smith 
2584a285bdaSBarry Smith     With refresh token entered in some way by the user
2594a285bdaSBarry Smith     PetscBoxRefresh(comm,refresh_token,access_token,sizeof(access_token));
2604a285bdaSBarry Smith     PetscBoxUpload(comm,access_token,filename);
2614a285bdaSBarry Smith 
2624a285bdaSBarry Smith     PetscBoxAuthorize(comm,access_token,refresh_token,sizeof(access_token));
2634a285bdaSBarry Smith     PetscBoxUpload(comm,access_token,filename);
264811af0c4SBarry Smith .ve
2654a285bdaSBarry Smith 
2662b26979fSBarry Smith    Level: intermediate
2672b26979fSBarry Smith 
268db781477SPatrick Sanan .seealso: `PetscURLShorten()`, `PetscBoxAuthorize()`, `PetscBoxRefresh()`
2694a285bdaSBarry Smith @*/
270d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscBoxUpload(MPI_Comm comm, const char access_token[], const char filename[])
271d71ae5a4SJacob Faibussowitsch {
2724a285bdaSBarry Smith   SSL_CTX    *ctx;
2734a285bdaSBarry Smith   SSL        *ssl;
2744a285bdaSBarry Smith   int         sock;
2754a285bdaSBarry Smith   char        head[1024], buff[8 * 1024], *body, *title;
2764a285bdaSBarry Smith   PetscMPIInt rank;
2774a285bdaSBarry Smith   struct stat sb;
2784a285bdaSBarry Smith   size_t      len, blen, rd;
2794a285bdaSBarry Smith   FILE       *fd;
2802da392ccSBarry Smith   int         err;
2814a285bdaSBarry Smith 
2824a285bdaSBarry Smith   PetscFunctionBegin;
2839566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
284dd400576SPatrick Sanan   if (rank == 0) {
285*c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(head, "Authorization: Bearer ", sizeof(head)));
286*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(head, access_token, sizeof(head)));
287*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(head, "\r\n", sizeof(head)));
288*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(head, "uploadType: multipart\r\n", sizeof(head)));
2894a285bdaSBarry Smith 
2902da392ccSBarry Smith     err = stat(filename, &sb);
29128b400f6SJacob Faibussowitsch     PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to stat file: %s", filename);
2924a285bdaSBarry Smith     len = 1024 + sb.st_size;
2939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(len, &body));
294*c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(body,
2954a285bdaSBarry Smith                            "--foo_bar_baz\r\n"
296*c6a7a370SJeremy L Thompson                            "Content-Type: application/json\r\n\r\n"
297*c6a7a370SJeremy L Thompson                            "{",
298*c6a7a370SJeremy L Thompson                            len));
299*c6a7a370SJeremy L Thompson     PetscCall(PetscPushJSONValue(body, "title", filename, len));
300*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", len));
301*c6a7a370SJeremy L Thompson     PetscCall(PetscPushJSONValue(body, "mimeType", "text.html", len));
302*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", len));
303*c6a7a370SJeremy L Thompson     PetscCall(PetscPushJSONValue(body, "description", "a file", len));
304*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body,
305*c6a7a370SJeremy L Thompson                            "}\r\n\r\n"
306*c6a7a370SJeremy L Thompson                            "--foo_bar_baz\r\n"
307*c6a7a370SJeremy L Thompson                            "Content-Type: text/html\r\n\r\n",
308*c6a7a370SJeremy L Thompson                            len));
3099566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(body, &blen));
3104a285bdaSBarry Smith     fd = fopen(filename, "r");
31128b400f6SJacob Faibussowitsch     PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open file: %s", filename);
3124a285bdaSBarry Smith     rd = fread(body + blen, sizeof(unsigned char), sb.st_size, fd);
313cc73adaaSBarry Smith     PetscCheck(rd == (size_t)sb.st_size, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to read entire file: %s %d %d", filename, (int)rd, (int)sb.st_size);
3144a285bdaSBarry Smith     fclose(fd);
3154a285bdaSBarry Smith     body[blen + rd] = 0;
316*c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body,
317*c6a7a370SJeremy L Thompson                            "\r\n\r\n"
318*c6a7a370SJeremy L Thompson                            "--foo_bar_baz\r\n",
319*c6a7a370SJeremy L Thompson                            len));
3209566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
3219566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("www.boxapis.com", 443, ctx, &sock, &ssl));
3229566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("POST", "www.boxapis.com/upload/drive/v2/files/", head, "multipart/related; boundary=\"foo_bar_baz\"", body, ssl, buff, sizeof(buff)));
3239566063dSJacob Faibussowitsch     PetscCall(PetscFree(body));
3249566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
3254a285bdaSBarry Smith     close(sock);
3269566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff, "\"title\"", &title));
32728b400f6SJacob Faibussowitsch     PetscCheck(title, PETSC_COMM_SELF, PETSC_ERR_LIB, "Upload of file %s failed", filename);
3284a285bdaSBarry Smith   }
3293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3304a285bdaSBarry Smith }
331