xref: /petsc/src/sys/webclient/box.c (revision 20f4b53cbb5e9bd9ef12b76a8697d60d197cda17)
14a285bdaSBarry Smith 
24a285bdaSBarry Smith #include <petscwebclient.h>
31c7e414eSJacob Faibussowitsch PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wdeprecated-declarations")
44a285bdaSBarry Smith 
54a285bdaSBarry Smith /*
64a285bdaSBarry Smith    These variables identify the code as a PETSc application to Box.
74a285bdaSBarry Smith 
8a8d69d7bSBarry Smith    See -   https://stackoverflow.com/questions/4616553/using-oauth-in-free-open-source-software
9a8d69d7bSBarry Smith    Users can get their own application IDs - goto https://developer.box.com
104a285bdaSBarry Smith 
114a285bdaSBarry Smith */
124a285bdaSBarry Smith #define PETSC_BOX_CLIENT_ID "sse42nygt4zqgrdwi0luv79q1u1f0xza"
134a285bdaSBarry Smith #define PETSC_BOX_CLIENT_ST "A0Dy4KgOYLB2JIYZqpbze4EzjeIiX5k4"
144a285bdaSBarry Smith 
15f044a08eSBarry Smith #if defined(PETSC_HAVE_SAWS)
164a285bdaSBarry Smith   #include <mongoose.h>
174a285bdaSBarry Smith 
184a285bdaSBarry Smith static volatile char *result = NULL;
194a285bdaSBarry Smith 
20d71ae5a4SJacob Faibussowitsch static int PetscBoxWebServer_Private(struct mg_connection *conn)
21d71ae5a4SJacob Faibussowitsch {
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 */
31d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscBoxStartWebServer_Private(void)
32d71ae5a4SJacob Faibussowitsch {
334a285bdaSBarry Smith   int                 optionsLen = 5;
344a285bdaSBarry Smith   const char         *options[optionsLen];
354a285bdaSBarry Smith   struct mg_callbacks callbacks;
364a285bdaSBarry Smith   struct mg_context  *ctx;
3768e69593SBarry Smith   char                keyfile[PETSC_MAX_PATH_LEN];
3868e69593SBarry Smith   PetscBool           exists;
394a285bdaSBarry Smith 
404a285bdaSBarry Smith   PetscFunctionBegin;
414a285bdaSBarry Smith   options[0] = "listening_ports";
424a285bdaSBarry Smith   options[1] = "8081s";
4368e69593SBarry Smith 
44c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(keyfile, "sslclient.pem", sizeof(keyfile)));
459566063dSJacob Faibussowitsch   PetscCall(PetscTestFile(keyfile, 'r', &exists));
4668e69593SBarry Smith   if (!exists) {
479566063dSJacob Faibussowitsch     PetscCall(PetscGetHomeDirectory(keyfile, PETSC_MAX_PATH_LEN));
48c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(keyfile, "/", sizeof(keyfile)));
49c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(keyfile, "sslclient.pem", sizeof(keyfile)));
509566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(keyfile, 'r', &exists));
5128b400f6SJacob Faibussowitsch     PetscCheck(exists, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate sslclient.pem file in current directory or home directory");
5268e69593SBarry Smith   }
5368e69593SBarry Smith 
544a285bdaSBarry Smith   options[2] = "ssl_certificate";
5568e69593SBarry Smith   options[3] = keyfile;
564a285bdaSBarry Smith   options[4] = NULL;
574a285bdaSBarry Smith 
584a285bdaSBarry Smith   /* Prepare callbacks structure. We have only one callback, the rest are NULL. */
599566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(&callbacks, sizeof(callbacks)));
604a285bdaSBarry Smith   callbacks.begin_request = PetscBoxWebServer_Private;
614a285bdaSBarry Smith   ctx                     = mg_start(&callbacks, NULL, options);
6228b400f6SJacob Faibussowitsch   PetscCheck(ctx, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to start up webserver");
634a285bdaSBarry Smith   while (!result) { };
643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
654a285bdaSBarry Smith }
664a285bdaSBarry Smith 
6768e69593SBarry Smith   #if defined(PETSC_HAVE_UNISTD_H)
6868e69593SBarry Smith     #include <unistd.h>
6968e69593SBarry Smith   #endif
7068e69593SBarry Smith 
714a285bdaSBarry Smith /*@C
724a285bdaSBarry Smith      PetscBoxAuthorize - Get authorization and refresh token for accessing Box drive from PETSc
734a285bdaSBarry Smith 
74*20f4b53cSBarry Smith    Not Collective, only the first rank in `MPI_Comm` does anything
754a285bdaSBarry Smith 
764a285bdaSBarry Smith    Input Parameters:
774a285bdaSBarry Smith +  comm - the MPI communicator
784a285bdaSBarry Smith -  tokensize - size of the token arrays
794a285bdaSBarry Smith 
804a285bdaSBarry Smith    Output Parameters:
81811af0c4SBarry Smith +  access_token - can be used with `PetscBoxUpload()` for this one session
82811af0c4SBarry Smith -  refresh_token - can be used for ever to obtain new access_tokens with `PetscBoxRefresh()`, guard this like a password
834a285bdaSBarry Smith                    it gives access to your Box Drive
844a285bdaSBarry Smith 
85*20f4b53cSBarry Smith    Level: intermediate
86*20f4b53cSBarry Smith 
8795452b02SPatrick Sanan    Notes:
88*20f4b53cSBarry Smith     This call requires `stdout` and `stdin` access from process 0 on the MPI communicator
894a285bdaSBarry Smith 
90c4762a1bSJed Brown    You can run src/sys/webclient/tutorials/boxobtainrefreshtoken to get a refresh token and then in the future pass it to
91*20f4b53cSBarry Smith    PETSc programs with `-box_refresh_token XXX`
924a285bdaSBarry Smith 
93*20f4b53cSBarry Smith    This requires PETSc be installed using `--with-saws` or `--download-saws`
94f044a08eSBarry Smith 
9568e69593SBarry Smith    Requires the user have created a self-signed ssl certificate with
96*20f4b53cSBarry Smith .vb
97*20f4b53cSBarry Smith     saws/CA.pl  -newcert  (using the passphrase of password)
98*20f4b53cSBarry Smith     cat newkey.pem newcert.pem > sslclient.pem
99*20f4b53cSBarry Smith .ve
10068e69593SBarry Smith     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
10168e69593SBarry Smith     silly but it was all I could figure out.
10268e69593SBarry Smith 
103db781477SPatrick Sanan .seealso: `PetscBoxRefresh()`, `PetscBoxUpload()`, `PetscURLShorten()`
1044a285bdaSBarry Smith @*/
105d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscBoxAuthorize(MPI_Comm comm, char access_token[], char refresh_token[], size_t tokensize)
106d71ae5a4SJacob Faibussowitsch {
1074a285bdaSBarry Smith   SSL_CTX    *ctx;
1084a285bdaSBarry Smith   SSL        *ssl;
1094a285bdaSBarry Smith   int         sock;
1105dc0f0a4SBarry Smith   char        buff[8 * 1024], body[1024];
1114a285bdaSBarry Smith   PetscMPIInt rank;
1125dc0f0a4SBarry Smith   PetscBool   flg, found;
1134a285bdaSBarry Smith 
1144a285bdaSBarry Smith   PetscFunctionBegin;
1159566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
116dd400576SPatrick Sanan   if (rank == 0) {
117cc73adaaSBarry Smith     PetscCheck(isatty(fileno(PETSC_STDOUT)), PETSC_COMM_SELF, PETSC_ERR_USER, "Requires users input/output");
118d0609cedSBarry Smith     PetscCall(PetscPrintf(comm, "Cut and paste the following into your browser:\n\n"
1194a285bdaSBarry Smith                                 "https://www.box.com/api/oauth2/authorize?"
1204a285bdaSBarry Smith                                 "response_type=code&"
1219371c9d4SSatish Balay                                 "client_id=" PETSC_BOX_CLIENT_ID "&state=PETScState"
122d0609cedSBarry Smith                                 "\n\n"));
1239566063dSJacob Faibussowitsch     PetscCall(PetscBoxStartWebServer_Private());
1249566063dSJacob Faibussowitsch     PetscCall(PetscStrbeginswith((const char *)result, "state=PETScState&code=", &flg));
12528b400f6SJacob Faibussowitsch     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_LIB, "Did not get expected string from Box got %s", result);
1269566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(buff, (const char *)result + 22, sizeof(buff)));
1274a285bdaSBarry Smith 
1289566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
1299566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("www.box.com", 443, ctx, &sock, &ssl));
130c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(body, "code=", sizeof(body)));
131c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, buff, sizeof(body)));
132c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "&client_id=", sizeof(body)));
133c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, PETSC_BOX_CLIENT_ID, sizeof(body)));
134c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "&client_secret=", sizeof(body)));
135c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, PETSC_BOX_CLIENT_ST, sizeof(body)));
136c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "&grant_type=authorization_code", sizeof(body)));
1374a285bdaSBarry Smith 
1389566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("POST", "www.box.com/api/oauth2/token", NULL, "application/x-www-form-urlencoded", body, ssl, buff, sizeof(buff)));
1399566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
1404a285bdaSBarry Smith     close(sock);
1414a285bdaSBarry Smith 
1429566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "access_token", access_token, tokensize, &found));
14328b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return access token");
1449566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "refresh_token", refresh_token, tokensize, &found));
14528b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return refresh token");
1464a285bdaSBarry Smith 
1479566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Here is your Box refresh token, save it in a save place, in the future you can run PETSc\n"));
1489566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "programs with the option -box_refresh_token %s\n", refresh_token));
1499566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "to access Box Drive automatically\n"));
1504a285bdaSBarry Smith   }
1513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1524a285bdaSBarry Smith }
153f044a08eSBarry Smith #endif
1544a285bdaSBarry Smith 
1554a285bdaSBarry Smith /*@C
1564a285bdaSBarry Smith      PetscBoxRefresh - Get a new authorization token for accessing Box drive from PETSc from a refresh token
1574a285bdaSBarry Smith 
158*20f4b53cSBarry Smith    Not Collective, only the first process in the `MPI_Comm` does anything
1594a285bdaSBarry Smith 
1604a285bdaSBarry Smith    Input Parameters:
1614a285bdaSBarry Smith +   comm - MPI communicator
162*20f4b53cSBarry Smith .   refresh token - obtained with `PetscBoxAuthorize()`, if `NULL` PETSc will first look for one in the options data
163811af0c4SBarry Smith                     if not found it will call `PetscBoxAuthorize()`
1644a285bdaSBarry Smith -   tokensize - size of the output string access_token
1654a285bdaSBarry Smith 
166d8d19677SJose E. Roman    Output Parameters:
167811af0c4SBarry Smith +   access_token - token that can be passed to `PetscBoxUpload()`
1684a285bdaSBarry 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
1694a285bdaSBarry Smith 
1702b26979fSBarry Smith    Level: intermediate
1712b26979fSBarry Smith 
172db781477SPatrick Sanan .seealso: `PetscURLShorten()`, `PetscBoxAuthorize()`, `PetscBoxUpload()`
1734a285bdaSBarry Smith @*/
174d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscBoxRefresh(MPI_Comm comm, const char refresh_token[], char access_token[], char new_refresh_token[], size_t tokensize)
175d71ae5a4SJacob Faibussowitsch {
1764a285bdaSBarry Smith   SSL_CTX    *ctx;
1774a285bdaSBarry Smith   SSL        *ssl;
1784a285bdaSBarry Smith   int         sock;
1795dc0f0a4SBarry Smith   char        buff[8 * 1024], body[1024];
1804a285bdaSBarry Smith   PetscMPIInt rank;
1815dc0f0a4SBarry Smith   char       *refreshtoken = (char *)refresh_token;
1825dc0f0a4SBarry Smith   PetscBool   found;
1834a285bdaSBarry Smith 
1844a285bdaSBarry Smith   PetscFunctionBegin;
1859566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
186dd400576SPatrick Sanan   if (rank == 0) {
1874a285bdaSBarry Smith     if (!refresh_token) {
1884a285bdaSBarry Smith       PetscBool set;
1899566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(512, &refreshtoken));
1909566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetString(NULL, NULL, "-box_refresh_token", refreshtoken, sizeof(refreshtoken), &set));
19199374591SBarry Smith #if defined(PETSC_HAVE_SAWS)
1924a285bdaSBarry Smith       if (!set) {
1939566063dSJacob Faibussowitsch         PetscCall(PetscBoxAuthorize(comm, access_token, new_refresh_token, 512 * sizeof(char)));
1949566063dSJacob Faibussowitsch         PetscCall(PetscFree(refreshtoken));
1953ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
1964a285bdaSBarry Smith       }
19799374591SBarry Smith #else
19828b400f6SJacob Faibussowitsch       PetscCheck(set, PETSC_COMM_SELF, PETSC_ERR_LIB, "Must provide refresh token with -box_refresh_token XXX");
19999374591SBarry Smith #endif
2004a285bdaSBarry Smith     }
2019566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
2029566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("www.box.com", 443, ctx, &sock, &ssl));
203c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(body, "client_id=", sizeof(body)));
204c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, PETSC_BOX_CLIENT_ID, sizeof(body)));
205c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "&client_secret=", sizeof(body)));
206c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, PETSC_BOX_CLIENT_ST, sizeof(body)));
207c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "&refresh_token=", sizeof(body)));
208c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, refreshtoken, sizeof(body)));
2099566063dSJacob Faibussowitsch     if (!refresh_token) PetscCall(PetscFree(refreshtoken));
210c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "&grant_type=refresh_token", sizeof(body)));
2114a285bdaSBarry Smith 
2129566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("POST", "www.box.com/api/oauth2/token", NULL, "application/x-www-form-urlencoded", body, ssl, buff, sizeof(buff)));
2139566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
2144a285bdaSBarry Smith     close(sock);
2154a285bdaSBarry Smith 
2169566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "access_token", access_token, tokensize, &found));
21728b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return access token");
2189566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "refresh_token", new_refresh_token, tokensize, &found));
21928b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return refresh token");
22093e1d32fSBarry Smith 
2219566063dSJacob 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"));
2229566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "programs with the option -box_refresh_token %s\n", new_refresh_token));
2239566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "to access Box Drive automatically\n"));
2244a285bdaSBarry Smith   }
2253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2264a285bdaSBarry Smith }
2274a285bdaSBarry Smith 
2284a285bdaSBarry Smith #include <sys/stat.h>
2294a285bdaSBarry Smith 
2304a285bdaSBarry Smith /*@C
2314a285bdaSBarry Smith      PetscBoxUpload - Loads a file to the Box Drive
2324a285bdaSBarry Smith 
23393e1d32fSBarry Smith      This routine has not yet been written; it is just copied from Google Drive
23493e1d32fSBarry Smith 
235811af0c4SBarry Smith      Not collective, only the first process in the `MPI_Comm` uploads the file
2364a285bdaSBarry Smith 
2374a285bdaSBarry Smith   Input Parameters:
2384a285bdaSBarry Smith +   comm - MPI communicator
239*20f4b53cSBarry Smith .   access_token - obtained with `PetscBoxRefresh()`, pass `NULL` to have PETSc generate one
2404a285bdaSBarry Smith -   filename - file to upload; if you upload multiple times it will have different names each time on Box Drive
2414a285bdaSBarry Smith 
242811af0c4SBarry Smith   Options Database Key:
24310699b91SBarry Smith .  -box_refresh_token XXX - the token value
2444a285bdaSBarry Smith 
2454a285bdaSBarry Smith   Usage Patterns:
246811af0c4SBarry Smith .vb
2474a285bdaSBarry Smith     With PETSc option -box_refresh_token XXX given
2484a285bdaSBarry Smith     PetscBoxUpload(comm,NULL,filename);        will upload file with no user interaction
2494a285bdaSBarry Smith 
2504a285bdaSBarry Smith     Without PETSc option -box_refresh_token XXX given
2514a285bdaSBarry Smith     PetscBoxUpload(comm,NULL,filename);        for first use will prompt user to authorize access to Box Drive with their processor
2524a285bdaSBarry Smith 
2534a285bdaSBarry Smith     With PETSc option -box_refresh_token  XXX given
2544a285bdaSBarry Smith     PetscBoxRefresh(comm,NULL,access_token,sizeof(access_token));
2554a285bdaSBarry Smith     PetscBoxUpload(comm,access_token,filename);
2564a285bdaSBarry Smith 
2574a285bdaSBarry Smith     With refresh token entered in some way by the user
2584a285bdaSBarry Smith     PetscBoxRefresh(comm,refresh_token,access_token,sizeof(access_token));
2594a285bdaSBarry Smith     PetscBoxUpload(comm,access_token,filename);
2604a285bdaSBarry Smith 
2614a285bdaSBarry Smith     PetscBoxAuthorize(comm,access_token,refresh_token,sizeof(access_token));
2624a285bdaSBarry Smith     PetscBoxUpload(comm,access_token,filename);
263811af0c4SBarry Smith .ve
2644a285bdaSBarry Smith 
2652b26979fSBarry Smith    Level: intermediate
2662b26979fSBarry Smith 
267db781477SPatrick Sanan .seealso: `PetscURLShorten()`, `PetscBoxAuthorize()`, `PetscBoxRefresh()`
2684a285bdaSBarry Smith @*/
269d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscBoxUpload(MPI_Comm comm, const char access_token[], const char filename[])
270d71ae5a4SJacob Faibussowitsch {
2714a285bdaSBarry Smith   SSL_CTX    *ctx;
2724a285bdaSBarry Smith   SSL        *ssl;
2734a285bdaSBarry Smith   int         sock;
2744a285bdaSBarry Smith   char        head[1024], buff[8 * 1024], *body, *title;
2754a285bdaSBarry Smith   PetscMPIInt rank;
2764a285bdaSBarry Smith   struct stat sb;
2774a285bdaSBarry Smith   size_t      len, blen, rd;
2784a285bdaSBarry Smith   FILE       *fd;
2792da392ccSBarry Smith   int         err;
2804a285bdaSBarry Smith 
2814a285bdaSBarry Smith   PetscFunctionBegin;
2829566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
283dd400576SPatrick Sanan   if (rank == 0) {
284c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(head, "Authorization: Bearer ", sizeof(head)));
285c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(head, access_token, sizeof(head)));
286c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(head, "\r\n", sizeof(head)));
287c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(head, "uploadType: multipart\r\n", sizeof(head)));
2884a285bdaSBarry Smith 
2892da392ccSBarry Smith     err = stat(filename, &sb);
29028b400f6SJacob Faibussowitsch     PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to stat file: %s", filename);
2914a285bdaSBarry Smith     len = 1024 + sb.st_size;
2929566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(len, &body));
293c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(body,
2944a285bdaSBarry Smith                            "--foo_bar_baz\r\n"
295c6a7a370SJeremy L Thompson                            "Content-Type: application/json\r\n\r\n"
296c6a7a370SJeremy L Thompson                            "{",
297c6a7a370SJeremy L Thompson                            len));
298c6a7a370SJeremy L Thompson     PetscCall(PetscPushJSONValue(body, "title", filename, len));
299c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", len));
300c6a7a370SJeremy L Thompson     PetscCall(PetscPushJSONValue(body, "mimeType", "text.html", len));
301c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", len));
302c6a7a370SJeremy L Thompson     PetscCall(PetscPushJSONValue(body, "description", "a file", len));
303c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body,
304c6a7a370SJeremy L Thompson                            "}\r\n\r\n"
305c6a7a370SJeremy L Thompson                            "--foo_bar_baz\r\n"
306c6a7a370SJeremy L Thompson                            "Content-Type: text/html\r\n\r\n",
307c6a7a370SJeremy L Thompson                            len));
3089566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(body, &blen));
3094a285bdaSBarry Smith     fd = fopen(filename, "r");
31028b400f6SJacob Faibussowitsch     PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open file: %s", filename);
3114a285bdaSBarry Smith     rd = fread(body + blen, sizeof(unsigned char), sb.st_size, fd);
312cc73adaaSBarry 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);
3134a285bdaSBarry Smith     fclose(fd);
3144a285bdaSBarry Smith     body[blen + rd] = 0;
315c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body,
316c6a7a370SJeremy L Thompson                            "\r\n\r\n"
317c6a7a370SJeremy L Thompson                            "--foo_bar_baz\r\n",
318c6a7a370SJeremy L Thompson                            len));
3199566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
3209566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("www.boxapis.com", 443, ctx, &sock, &ssl));
3219566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("POST", "www.boxapis.com/upload/drive/v2/files/", head, "multipart/related; boundary=\"foo_bar_baz\"", body, ssl, buff, sizeof(buff)));
3229566063dSJacob Faibussowitsch     PetscCall(PetscFree(body));
3239566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
3244a285bdaSBarry Smith     close(sock);
3259566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff, "\"title\"", &title));
32628b400f6SJacob Faibussowitsch     PetscCheck(title, PETSC_COMM_SELF, PETSC_ERR_LIB, "Upload of file %s failed", filename);
3274a285bdaSBarry Smith   }
3283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3294a285bdaSBarry Smith }
330