xref: /petsc/src/sys/webclient/box.c (revision 811af0c4b09a35de4306c442f88bd09fdc09897d)
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 
219371c9d4SSatish Balay static int PetscBoxWebServer_Private(struct mg_connection *conn) {
224a285bdaSBarry Smith   const struct mg_request_info *request_info = mg_get_request_info(conn);
234a285bdaSBarry Smith   result                                     = (char *)request_info->query_string;
24f044a08eSBarry Smith   return 1; /* Mongoose will now not handle the request */
254a285bdaSBarry Smith }
264a285bdaSBarry Smith 
27f044a08eSBarry Smith /*
28f044a08eSBarry Smith     Box can only return an authorization code to a Webserver, hence we need to start one up and wait for
29f044a08eSBarry Smith     the authorization code to arrive from Box
30f044a08eSBarry Smith */
319371c9d4SSatish Balay static PetscErrorCode PetscBoxStartWebServer_Private(void) {
324a285bdaSBarry Smith   int                 optionsLen = 5;
334a285bdaSBarry Smith   const char         *options[optionsLen];
344a285bdaSBarry Smith   struct mg_callbacks callbacks;
354a285bdaSBarry Smith   struct mg_context  *ctx;
3668e69593SBarry Smith   char                keyfile[PETSC_MAX_PATH_LEN];
3768e69593SBarry Smith   PetscBool           exists;
384a285bdaSBarry Smith 
394a285bdaSBarry Smith   PetscFunctionBegin;
404a285bdaSBarry Smith   options[0] = "listening_ports";
414a285bdaSBarry Smith   options[1] = "8081s";
4268e69593SBarry Smith 
439566063dSJacob Faibussowitsch   PetscCall(PetscStrcpy(keyfile, "sslclient.pem"));
449566063dSJacob Faibussowitsch   PetscCall(PetscTestFile(keyfile, 'r', &exists));
4568e69593SBarry Smith   if (!exists) {
469566063dSJacob Faibussowitsch     PetscCall(PetscGetHomeDirectory(keyfile, PETSC_MAX_PATH_LEN));
479566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(keyfile, "/"));
489566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(keyfile, "sslclient.pem"));
499566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(keyfile, 'r', &exists));
5028b400f6SJacob Faibussowitsch     PetscCheck(exists, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate sslclient.pem file in current directory or home directory");
5168e69593SBarry Smith   }
5268e69593SBarry Smith 
534a285bdaSBarry Smith   options[2] = "ssl_certificate";
5468e69593SBarry Smith   options[3] = keyfile;
554a285bdaSBarry Smith   options[4] = NULL;
564a285bdaSBarry Smith 
574a285bdaSBarry Smith   /* Prepare callbacks structure. We have only one callback, the rest are NULL. */
589566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(&callbacks, sizeof(callbacks)));
594a285bdaSBarry Smith   callbacks.begin_request = PetscBoxWebServer_Private;
604a285bdaSBarry Smith   ctx                     = mg_start(&callbacks, NULL, options);
6128b400f6SJacob Faibussowitsch   PetscCheck(ctx, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to start up webserver");
624a285bdaSBarry Smith   while (!result) { };
634a285bdaSBarry Smith   PetscFunctionReturn(0);
644a285bdaSBarry Smith }
654a285bdaSBarry Smith 
6668e69593SBarry Smith #if defined(PETSC_HAVE_UNISTD_H)
6768e69593SBarry Smith #include <unistd.h>
6868e69593SBarry Smith #endif
6968e69593SBarry Smith 
704a285bdaSBarry Smith /*@C
714a285bdaSBarry Smith      PetscBoxAuthorize - Get authorization and refresh token for accessing Box drive from PETSc
724a285bdaSBarry Smith 
73*811af0c4SBarry Smith    Not collective, only the first rank in `MPI_Comm` does anything
744a285bdaSBarry Smith 
754a285bdaSBarry Smith    Input Parameters:
764a285bdaSBarry Smith +  comm - the MPI communicator
774a285bdaSBarry Smith -  tokensize - size of the token arrays
784a285bdaSBarry Smith 
794a285bdaSBarry Smith    Output Parameters:
80*811af0c4SBarry Smith +  access_token - can be used with `PetscBoxUpload()` for this one session
81*811af0c4SBarry Smith -  refresh_token - can be used for ever to obtain new access_tokens with `PetscBoxRefresh()`, guard this like a password
824a285bdaSBarry Smith                    it gives access to your Box Drive
834a285bdaSBarry Smith 
8495452b02SPatrick Sanan    Notes:
8595452b02SPatrick Sanan     This call requires stdout and stdin access from process 0 on the MPI communicator
864a285bdaSBarry Smith 
87c4762a1bSJed Brown    You can run src/sys/webclient/tutorials/boxobtainrefreshtoken to get a refresh token and then in the future pass it to
884a285bdaSBarry Smith    PETSc programs with -box_refresh_token XXX
894a285bdaSBarry Smith 
90f044a08eSBarry Smith    This requires PETSc be installed using --with-saws or --download-saws
91f044a08eSBarry Smith 
9268e69593SBarry Smith    Requires the user have created a self-signed ssl certificate with
9368e69593SBarry Smith 
9468e69593SBarry Smith $    saws/CA.pl  -newcert  (using the passphrase of password)
9568e69593SBarry Smith $    cat newkey.pem newcert.pem > sslclient.pem
9668e69593SBarry Smith 
9768e69593SBarry Smith     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
9868e69593SBarry Smith     silly but it was all I could figure out.
9968e69593SBarry Smith 
1002b26979fSBarry Smith    Level: intermediate
1012b26979fSBarry Smith 
102db781477SPatrick Sanan .seealso: `PetscBoxRefresh()`, `PetscBoxUpload()`, `PetscURLShorten()`
1034a285bdaSBarry Smith @*/
1049371c9d4SSatish Balay PetscErrorCode PetscBoxAuthorize(MPI_Comm comm, char access_token[], char refresh_token[], size_t tokensize) {
1054a285bdaSBarry Smith   SSL_CTX    *ctx;
1064a285bdaSBarry Smith   SSL        *ssl;
1074a285bdaSBarry Smith   int         sock;
1085dc0f0a4SBarry Smith   char        buff[8 * 1024], body[1024];
1094a285bdaSBarry Smith   PetscMPIInt rank;
1105dc0f0a4SBarry Smith   PetscBool   flg, found;
1114a285bdaSBarry Smith 
1124a285bdaSBarry Smith   PetscFunctionBegin;
1139566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
114dd400576SPatrick Sanan   if (rank == 0) {
115cc73adaaSBarry Smith     PetscCheck(isatty(fileno(PETSC_STDOUT)), PETSC_COMM_SELF, PETSC_ERR_USER, "Requires users input/output");
116d0609cedSBarry Smith     PetscCall(PetscPrintf(comm, "Cut and paste the following into your browser:\n\n"
1174a285bdaSBarry Smith                                 "https://www.box.com/api/oauth2/authorize?"
1184a285bdaSBarry Smith                                 "response_type=code&"
1199371c9d4SSatish Balay                                 "client_id=" PETSC_BOX_CLIENT_ID "&state=PETScState"
120d0609cedSBarry Smith                                 "\n\n"));
1219566063dSJacob Faibussowitsch     PetscCall(PetscBoxStartWebServer_Private());
1229566063dSJacob Faibussowitsch     PetscCall(PetscStrbeginswith((const char *)result, "state=PETScState&code=", &flg));
12328b400f6SJacob Faibussowitsch     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_LIB, "Did not get expected string from Box got %s", result);
1249566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(buff, (const char *)result + 22, sizeof(buff)));
1254a285bdaSBarry Smith 
1269566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
1279566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("www.box.com", 443, ctx, &sock, &ssl));
1289566063dSJacob Faibussowitsch     PetscCall(PetscStrcpy(body, "code="));
1299566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, buff));
1309566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, "&client_id="));
1319566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, PETSC_BOX_CLIENT_ID));
1329566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, "&client_secret="));
1339566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, PETSC_BOX_CLIENT_ST));
1349566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, "&grant_type=authorization_code"));
1354a285bdaSBarry Smith 
1369566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("POST", "www.box.com/api/oauth2/token", NULL, "application/x-www-form-urlencoded", body, ssl, buff, sizeof(buff)));
1379566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
1384a285bdaSBarry Smith     close(sock);
1394a285bdaSBarry Smith 
1409566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "access_token", access_token, tokensize, &found));
14128b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return access token");
1429566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "refresh_token", refresh_token, tokensize, &found));
14328b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return refresh token");
1444a285bdaSBarry Smith 
1459566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Here is your Box refresh token, save it in a save place, in the future you can run PETSc\n"));
1469566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "programs with the option -box_refresh_token %s\n", refresh_token));
1479566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "to access Box Drive automatically\n"));
1484a285bdaSBarry Smith   }
1494a285bdaSBarry Smith   PetscFunctionReturn(0);
1504a285bdaSBarry Smith }
151f044a08eSBarry Smith #endif
1524a285bdaSBarry Smith 
1534a285bdaSBarry Smith /*@C
1544a285bdaSBarry Smith      PetscBoxRefresh - Get a new authorization token for accessing Box drive from PETSc from a refresh token
1554a285bdaSBarry Smith 
156*811af0c4SBarry Smith    Not collective, only the first process in the `MPI_Comm` does anything
1574a285bdaSBarry Smith 
1584a285bdaSBarry Smith    Input Parameters:
1594a285bdaSBarry Smith +   comm - MPI communicator
160*811af0c4SBarry Smith .   refresh token - obtained with `PetscBoxAuthorize()`, if NULL PETSc will first look for one in the options data
161*811af0c4SBarry Smith                     if not found it will call `PetscBoxAuthorize()`
1624a285bdaSBarry Smith -   tokensize - size of the output string access_token
1634a285bdaSBarry Smith 
164d8d19677SJose E. Roman    Output Parameters:
165*811af0c4SBarry Smith +   access_token - token that can be passed to `PetscBoxUpload()`
1664a285bdaSBarry 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
1674a285bdaSBarry Smith 
1682b26979fSBarry Smith    Level: intermediate
1692b26979fSBarry Smith 
170db781477SPatrick Sanan .seealso: `PetscURLShorten()`, `PetscBoxAuthorize()`, `PetscBoxUpload()`
1714a285bdaSBarry Smith @*/
1729371c9d4SSatish Balay PetscErrorCode PetscBoxRefresh(MPI_Comm comm, const char refresh_token[], char access_token[], char new_refresh_token[], size_t tokensize) {
1734a285bdaSBarry Smith   SSL_CTX    *ctx;
1744a285bdaSBarry Smith   SSL        *ssl;
1754a285bdaSBarry Smith   int         sock;
1765dc0f0a4SBarry Smith   char        buff[8 * 1024], body[1024];
1774a285bdaSBarry Smith   PetscMPIInt rank;
1785dc0f0a4SBarry Smith   char       *refreshtoken = (char *)refresh_token;
1795dc0f0a4SBarry Smith   PetscBool   found;
1804a285bdaSBarry Smith 
1814a285bdaSBarry Smith   PetscFunctionBegin;
1829566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
183dd400576SPatrick Sanan   if (rank == 0) {
1844a285bdaSBarry Smith     if (!refresh_token) {
1854a285bdaSBarry Smith       PetscBool set;
1869566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(512, &refreshtoken));
1879566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetString(NULL, NULL, "-box_refresh_token", refreshtoken, sizeof(refreshtoken), &set));
18899374591SBarry Smith #if defined(PETSC_HAVE_SAWS)
1894a285bdaSBarry Smith       if (!set) {
1909566063dSJacob Faibussowitsch         PetscCall(PetscBoxAuthorize(comm, access_token, new_refresh_token, 512 * sizeof(char)));
1919566063dSJacob Faibussowitsch         PetscCall(PetscFree(refreshtoken));
1924a285bdaSBarry Smith         PetscFunctionReturn(0);
1934a285bdaSBarry Smith       }
19499374591SBarry Smith #else
19528b400f6SJacob Faibussowitsch       PetscCheck(set, PETSC_COMM_SELF, PETSC_ERR_LIB, "Must provide refresh token with -box_refresh_token XXX");
19699374591SBarry Smith #endif
1974a285bdaSBarry Smith     }
1989566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
1999566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("www.box.com", 443, ctx, &sock, &ssl));
2009566063dSJacob Faibussowitsch     PetscCall(PetscStrcpy(body, "client_id="));
2019566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, PETSC_BOX_CLIENT_ID));
2029566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, "&client_secret="));
2039566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, PETSC_BOX_CLIENT_ST));
2049566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, "&refresh_token="));
2059566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, refreshtoken));
2069566063dSJacob Faibussowitsch     if (!refresh_token) PetscCall(PetscFree(refreshtoken));
2079566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, "&grant_type=refresh_token"));
2084a285bdaSBarry Smith 
2099566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("POST", "www.box.com/api/oauth2/token", NULL, "application/x-www-form-urlencoded", body, ssl, buff, sizeof(buff)));
2109566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
2114a285bdaSBarry Smith     close(sock);
2124a285bdaSBarry Smith 
2139566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "access_token", access_token, tokensize, &found));
21428b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return access token");
2159566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "refresh_token", new_refresh_token, tokensize, &found));
21628b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return refresh token");
21793e1d32fSBarry Smith 
2189566063dSJacob 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"));
2199566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "programs with the option -box_refresh_token %s\n", new_refresh_token));
2209566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "to access Box Drive automatically\n"));
2214a285bdaSBarry Smith   }
2224a285bdaSBarry Smith   PetscFunctionReturn(0);
2234a285bdaSBarry Smith }
2244a285bdaSBarry Smith 
2254a285bdaSBarry Smith #include <sys/stat.h>
2264a285bdaSBarry Smith 
2274a285bdaSBarry Smith /*@C
2284a285bdaSBarry Smith      PetscBoxUpload - Loads a file to the Box Drive
2294a285bdaSBarry Smith 
23093e1d32fSBarry Smith      This routine has not yet been written; it is just copied from Google Drive
23193e1d32fSBarry Smith 
232*811af0c4SBarry Smith      Not collective, only the first process in the `MPI_Comm` uploads the file
2334a285bdaSBarry Smith 
2344a285bdaSBarry Smith   Input Parameters:
2354a285bdaSBarry Smith +   comm - MPI communicator
236*811af0c4SBarry Smith .   access_token - obtained with `PetscBoxRefresh()`, pass NULL to have PETSc generate one
2374a285bdaSBarry Smith -   filename - file to upload; if you upload multiple times it will have different names each time on Box Drive
2384a285bdaSBarry Smith 
239*811af0c4SBarry Smith   Options Database Key:
24010699b91SBarry Smith .  -box_refresh_token XXX - the token value
2414a285bdaSBarry Smith 
2424a285bdaSBarry Smith   Usage Patterns:
243*811af0c4SBarry Smith .vb
2444a285bdaSBarry Smith     With PETSc option -box_refresh_token XXX given
2454a285bdaSBarry Smith     PetscBoxUpload(comm,NULL,filename);        will upload file with no user interaction
2464a285bdaSBarry Smith 
2474a285bdaSBarry Smith     Without PETSc option -box_refresh_token XXX given
2484a285bdaSBarry Smith     PetscBoxUpload(comm,NULL,filename);        for first use will prompt user to authorize access to Box Drive with their processor
2494a285bdaSBarry Smith 
2504a285bdaSBarry Smith     With PETSc option -box_refresh_token  XXX given
2514a285bdaSBarry Smith     PetscBoxRefresh(comm,NULL,access_token,sizeof(access_token));
2524a285bdaSBarry Smith     PetscBoxUpload(comm,access_token,filename);
2534a285bdaSBarry Smith 
2544a285bdaSBarry Smith     With refresh token entered in some way by the user
2554a285bdaSBarry Smith     PetscBoxRefresh(comm,refresh_token,access_token,sizeof(access_token));
2564a285bdaSBarry Smith     PetscBoxUpload(comm,access_token,filename);
2574a285bdaSBarry Smith 
2584a285bdaSBarry Smith     PetscBoxAuthorize(comm,access_token,refresh_token,sizeof(access_token));
2594a285bdaSBarry Smith     PetscBoxUpload(comm,access_token,filename);
260*811af0c4SBarry Smith .ve
2614a285bdaSBarry Smith 
2622b26979fSBarry Smith    Level: intermediate
2632b26979fSBarry Smith 
264db781477SPatrick Sanan .seealso: `PetscURLShorten()`, `PetscBoxAuthorize()`, `PetscBoxRefresh()`
2654a285bdaSBarry Smith @*/
2669371c9d4SSatish Balay PetscErrorCode PetscBoxUpload(MPI_Comm comm, const char access_token[], const char filename[]) {
2674a285bdaSBarry Smith   SSL_CTX    *ctx;
2684a285bdaSBarry Smith   SSL        *ssl;
2694a285bdaSBarry Smith   int         sock;
2704a285bdaSBarry Smith   char        head[1024], buff[8 * 1024], *body, *title;
2714a285bdaSBarry Smith   PetscMPIInt rank;
2724a285bdaSBarry Smith   struct stat sb;
2734a285bdaSBarry Smith   size_t      len, blen, rd;
2744a285bdaSBarry Smith   FILE       *fd;
2752da392ccSBarry Smith   int         err;
2764a285bdaSBarry Smith 
2774a285bdaSBarry Smith   PetscFunctionBegin;
2789566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
279dd400576SPatrick Sanan   if (rank == 0) {
2809566063dSJacob Faibussowitsch     PetscCall(PetscStrcpy(head, "Authorization: Bearer "));
2819566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(head, access_token));
2829566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(head, "\r\n"));
2839566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(head, "uploadType: multipart\r\n"));
2844a285bdaSBarry Smith 
2852da392ccSBarry Smith     err = stat(filename, &sb);
28628b400f6SJacob Faibussowitsch     PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to stat file: %s", filename);
2874a285bdaSBarry Smith     len = 1024 + sb.st_size;
2889566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(len, &body));
289d0609cedSBarry Smith     PetscCall(PetscStrcpy(body, "--foo_bar_baz\r\n"
2904a285bdaSBarry Smith                                 "Content-Type: application/json\r\n\r\n"
291d0609cedSBarry Smith                                 "{"));
2929566063dSJacob Faibussowitsch     PetscCall(PetscPushJSONValue(body, "title", filename, len));
2939566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, ","));
2949566063dSJacob Faibussowitsch     PetscCall(PetscPushJSONValue(body, "mimeType", "text.html", len));
2959566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, ","));
2969566063dSJacob Faibussowitsch     PetscCall(PetscPushJSONValue(body, "description", "a file", len));
297d8174014SToby Isaac     PetscCall(PetscStrcat(body, "}\r\n\r\n"
2984a285bdaSBarry Smith                                 "--foo_bar_baz\r\n"
299d0609cedSBarry Smith                                 "Content-Type: text/html\r\n\r\n"));
3009566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(body, &blen));
3014a285bdaSBarry Smith     fd = fopen(filename, "r");
30228b400f6SJacob Faibussowitsch     PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open file: %s", filename);
3034a285bdaSBarry Smith     rd = fread(body + blen, sizeof(unsigned char), sb.st_size, fd);
304cc73adaaSBarry 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);
3054a285bdaSBarry Smith     fclose(fd);
3064a285bdaSBarry Smith     body[blen + rd] = 0;
307d0609cedSBarry Smith     PetscCall(PetscStrcat(body, "\r\n\r\n"
308d0609cedSBarry Smith                                 "--foo_bar_baz\r\n"));
3099566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
3109566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("www.boxapis.com", 443, ctx, &sock, &ssl));
3119566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("POST", "www.boxapis.com/upload/drive/v2/files/", head, "multipart/related; boundary=\"foo_bar_baz\"", body, ssl, buff, sizeof(buff)));
3129566063dSJacob Faibussowitsch     PetscCall(PetscFree(body));
3139566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
3144a285bdaSBarry Smith     close(sock);
3159566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff, "\"title\"", &title));
31628b400f6SJacob Faibussowitsch     PetscCheck(title, PETSC_COMM_SELF, PETSC_ERR_LIB, "Upload of file %s failed", filename);
3174a285bdaSBarry Smith   }
3184a285bdaSBarry Smith   PetscFunctionReturn(0);
3194a285bdaSBarry Smith }
320