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 21*9371c9d4SSatish 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 */ 31*9371c9d4SSatish 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 734a285bdaSBarry Smith Not collective, only the first process 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: 804a285bdaSBarry Smith + access_token - can be used with PetscBoxUpload() for this one session 814a285bdaSBarry 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 1044a285bdaSBarry Smith @*/ 105*9371c9d4SSatish Balay PetscErrorCode PetscBoxAuthorize(MPI_Comm comm, char access_token[], char refresh_token[], size_t tokensize) { 1064a285bdaSBarry Smith SSL_CTX *ctx; 1074a285bdaSBarry Smith SSL *ssl; 1084a285bdaSBarry Smith int sock; 1095dc0f0a4SBarry Smith char buff[8 * 1024], body[1024]; 1104a285bdaSBarry Smith PetscMPIInt rank; 1115dc0f0a4SBarry Smith PetscBool flg, found; 1124a285bdaSBarry Smith 1134a285bdaSBarry Smith PetscFunctionBegin; 1149566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 115dd400576SPatrick Sanan if (rank == 0) { 116cc73adaaSBarry Smith PetscCheck(isatty(fileno(PETSC_STDOUT)), PETSC_COMM_SELF, PETSC_ERR_USER, "Requires users input/output"); 117d0609cedSBarry Smith PetscCall(PetscPrintf(comm, "Cut and paste the following into your browser:\n\n" 1184a285bdaSBarry Smith "https://www.box.com/api/oauth2/authorize?" 1194a285bdaSBarry Smith "response_type=code&" 120*9371c9d4SSatish Balay "client_id=" PETSC_BOX_CLIENT_ID "&state=PETScState" 121d0609cedSBarry Smith "\n\n")); 1229566063dSJacob Faibussowitsch PetscCall(PetscBoxStartWebServer_Private()); 1239566063dSJacob Faibussowitsch PetscCall(PetscStrbeginswith((const char *)result, "state=PETScState&code=", &flg)); 12428b400f6SJacob Faibussowitsch PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_LIB, "Did not get expected string from Box got %s", result); 1259566063dSJacob Faibussowitsch PetscCall(PetscStrncpy(buff, (const char *)result + 22, sizeof(buff))); 1264a285bdaSBarry Smith 1279566063dSJacob Faibussowitsch PetscCall(PetscSSLInitializeContext(&ctx)); 1289566063dSJacob Faibussowitsch PetscCall(PetscHTTPSConnect("www.box.com", 443, ctx, &sock, &ssl)); 1299566063dSJacob Faibussowitsch PetscCall(PetscStrcpy(body, "code=")); 1309566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, buff)); 1319566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, "&client_id=")); 1329566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, PETSC_BOX_CLIENT_ID)); 1339566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, "&client_secret=")); 1349566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, PETSC_BOX_CLIENT_ST)); 1359566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, "&grant_type=authorization_code")); 1364a285bdaSBarry Smith 1379566063dSJacob Faibussowitsch PetscCall(PetscHTTPSRequest("POST", "www.box.com/api/oauth2/token", NULL, "application/x-www-form-urlencoded", body, ssl, buff, sizeof(buff))); 1389566063dSJacob Faibussowitsch PetscCall(PetscSSLDestroyContext(ctx)); 1394a285bdaSBarry Smith close(sock); 1404a285bdaSBarry Smith 1419566063dSJacob Faibussowitsch PetscCall(PetscPullJSONValue(buff, "access_token", access_token, tokensize, &found)); 14228b400f6SJacob Faibussowitsch PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return access token"); 1439566063dSJacob Faibussowitsch PetscCall(PetscPullJSONValue(buff, "refresh_token", refresh_token, tokensize, &found)); 14428b400f6SJacob Faibussowitsch PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return refresh token"); 1454a285bdaSBarry Smith 1469566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "Here is your Box refresh token, save it in a save place, in the future you can run PETSc\n")); 1479566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "programs with the option -box_refresh_token %s\n", refresh_token)); 1489566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "to access Box Drive automatically\n")); 1494a285bdaSBarry Smith } 1504a285bdaSBarry Smith PetscFunctionReturn(0); 1514a285bdaSBarry Smith } 152f044a08eSBarry Smith #endif 1534a285bdaSBarry Smith 1544a285bdaSBarry Smith /*@C 1554a285bdaSBarry Smith PetscBoxRefresh - Get a new authorization token for accessing Box drive from PETSc from a refresh token 1564a285bdaSBarry Smith 1574a285bdaSBarry Smith Not collective, only the first process in the MPI_Comm does anything 1584a285bdaSBarry Smith 1594a285bdaSBarry Smith Input Parameters: 1604a285bdaSBarry Smith + comm - MPI communicator 1614a285bdaSBarry Smith . refresh token - obtained with PetscBoxAuthorize(), if NULL PETSc will first look for one in the options data 1624a285bdaSBarry Smith if not found it will call PetscBoxAuthorize() 1634a285bdaSBarry Smith - tokensize - size of the output string access_token 1644a285bdaSBarry Smith 165d8d19677SJose E. Roman Output Parameters: 1664a285bdaSBarry Smith + access_token - token that can be passed to PetscBoxUpload() 1674a285bdaSBarry 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 1684a285bdaSBarry Smith 1692b26979fSBarry Smith Level: intermediate 1702b26979fSBarry Smith 171db781477SPatrick Sanan .seealso: `PetscURLShorten()`, `PetscBoxAuthorize()`, `PetscBoxUpload()` 1724a285bdaSBarry Smith 1734a285bdaSBarry Smith @*/ 174*9371c9d4SSatish Balay PetscErrorCode PetscBoxRefresh(MPI_Comm comm, const char refresh_token[], char access_token[], char new_refresh_token[], size_t tokensize) { 1754a285bdaSBarry Smith SSL_CTX *ctx; 1764a285bdaSBarry Smith SSL *ssl; 1774a285bdaSBarry Smith int sock; 1785dc0f0a4SBarry Smith char buff[8 * 1024], body[1024]; 1794a285bdaSBarry Smith PetscMPIInt rank; 1805dc0f0a4SBarry Smith char *refreshtoken = (char *)refresh_token; 1815dc0f0a4SBarry Smith PetscBool found; 1824a285bdaSBarry Smith 1834a285bdaSBarry Smith PetscFunctionBegin; 1849566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 185dd400576SPatrick Sanan if (rank == 0) { 1864a285bdaSBarry Smith if (!refresh_token) { 1874a285bdaSBarry Smith PetscBool set; 1889566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(512, &refreshtoken)); 1899566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetString(NULL, NULL, "-box_refresh_token", refreshtoken, sizeof(refreshtoken), &set)); 19099374591SBarry Smith #if defined(PETSC_HAVE_SAWS) 1914a285bdaSBarry Smith if (!set) { 1929566063dSJacob Faibussowitsch PetscCall(PetscBoxAuthorize(comm, access_token, new_refresh_token, 512 * sizeof(char))); 1939566063dSJacob Faibussowitsch PetscCall(PetscFree(refreshtoken)); 1944a285bdaSBarry Smith PetscFunctionReturn(0); 1954a285bdaSBarry Smith } 19699374591SBarry Smith #else 19728b400f6SJacob Faibussowitsch PetscCheck(set, PETSC_COMM_SELF, PETSC_ERR_LIB, "Must provide refresh token with -box_refresh_token XXX"); 19899374591SBarry Smith #endif 1994a285bdaSBarry Smith } 2009566063dSJacob Faibussowitsch PetscCall(PetscSSLInitializeContext(&ctx)); 2019566063dSJacob Faibussowitsch PetscCall(PetscHTTPSConnect("www.box.com", 443, ctx, &sock, &ssl)); 2029566063dSJacob Faibussowitsch PetscCall(PetscStrcpy(body, "client_id=")); 2039566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, PETSC_BOX_CLIENT_ID)); 2049566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, "&client_secret=")); 2059566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, PETSC_BOX_CLIENT_ST)); 2069566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, "&refresh_token=")); 2079566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, refreshtoken)); 2089566063dSJacob Faibussowitsch if (!refresh_token) PetscCall(PetscFree(refreshtoken)); 2099566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, "&grant_type=refresh_token")); 2104a285bdaSBarry Smith 2119566063dSJacob Faibussowitsch PetscCall(PetscHTTPSRequest("POST", "www.box.com/api/oauth2/token", NULL, "application/x-www-form-urlencoded", body, ssl, buff, sizeof(buff))); 2129566063dSJacob Faibussowitsch PetscCall(PetscSSLDestroyContext(ctx)); 2134a285bdaSBarry Smith close(sock); 2144a285bdaSBarry Smith 2159566063dSJacob Faibussowitsch PetscCall(PetscPullJSONValue(buff, "access_token", access_token, tokensize, &found)); 21628b400f6SJacob Faibussowitsch PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return access token"); 2179566063dSJacob Faibussowitsch PetscCall(PetscPullJSONValue(buff, "refresh_token", new_refresh_token, tokensize, &found)); 21828b400f6SJacob Faibussowitsch PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Box did not return refresh token"); 21993e1d32fSBarry Smith 2209566063dSJacob 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")); 2219566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "programs with the option -box_refresh_token %s\n", new_refresh_token)); 2229566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "to access Box Drive automatically\n")); 2234a285bdaSBarry Smith } 2244a285bdaSBarry Smith PetscFunctionReturn(0); 2254a285bdaSBarry Smith } 2264a285bdaSBarry Smith 2274a285bdaSBarry Smith #include <sys/stat.h> 2284a285bdaSBarry Smith 2294a285bdaSBarry Smith /*@C 2304a285bdaSBarry Smith PetscBoxUpload - Loads a file to the Box Drive 2314a285bdaSBarry Smith 23293e1d32fSBarry Smith This routine has not yet been written; it is just copied from Google Drive 23393e1d32fSBarry Smith 2344a285bdaSBarry Smith Not collective, only the first process in the MPI_Comm uploads the file 2354a285bdaSBarry Smith 2364a285bdaSBarry Smith Input Parameters: 2374a285bdaSBarry Smith + comm - MPI communicator 2384a285bdaSBarry Smith . access_token - obtained with PetscBoxRefresh(), pass NULL to have PETSc generate one 2394a285bdaSBarry Smith - filename - file to upload; if you upload multiple times it will have different names each time on Box Drive 2404a285bdaSBarry Smith 2414a285bdaSBarry Smith Options Database: 24210699b91SBarry Smith . -box_refresh_token XXX - the token value 2434a285bdaSBarry Smith 2444a285bdaSBarry Smith Usage Patterns: 2454a285bdaSBarry Smith With PETSc option -box_refresh_token XXX given 2464a285bdaSBarry Smith PetscBoxUpload(comm,NULL,filename); will upload file with no user interaction 2474a285bdaSBarry Smith 2484a285bdaSBarry Smith Without PETSc option -box_refresh_token XXX given 2494a285bdaSBarry Smith PetscBoxUpload(comm,NULL,filename); for first use will prompt user to authorize access to Box Drive with their processor 2504a285bdaSBarry Smith 2514a285bdaSBarry Smith With PETSc option -box_refresh_token XXX given 2524a285bdaSBarry Smith PetscBoxRefresh(comm,NULL,access_token,sizeof(access_token)); 2534a285bdaSBarry Smith PetscBoxUpload(comm,access_token,filename); 2544a285bdaSBarry Smith 2554a285bdaSBarry Smith With refresh token entered in some way by the user 2564a285bdaSBarry Smith PetscBoxRefresh(comm,refresh_token,access_token,sizeof(access_token)); 2574a285bdaSBarry Smith PetscBoxUpload(comm,access_token,filename); 2584a285bdaSBarry Smith 2594a285bdaSBarry Smith PetscBoxAuthorize(comm,access_token,refresh_token,sizeof(access_token)); 2604a285bdaSBarry Smith PetscBoxUpload(comm,access_token,filename); 2614a285bdaSBarry Smith 2622b26979fSBarry Smith Level: intermediate 2632b26979fSBarry Smith 264db781477SPatrick Sanan .seealso: `PetscURLShorten()`, `PetscBoxAuthorize()`, `PetscBoxRefresh()` 2654a285bdaSBarry Smith 2664a285bdaSBarry Smith @*/ 267*9371c9d4SSatish Balay PetscErrorCode PetscBoxUpload(MPI_Comm comm, const char access_token[], const char filename[]) { 2684a285bdaSBarry Smith SSL_CTX *ctx; 2694a285bdaSBarry Smith SSL *ssl; 2704a285bdaSBarry Smith int sock; 2714a285bdaSBarry Smith char head[1024], buff[8 * 1024], *body, *title; 2724a285bdaSBarry Smith PetscMPIInt rank; 2734a285bdaSBarry Smith struct stat sb; 2744a285bdaSBarry Smith size_t len, blen, rd; 2754a285bdaSBarry Smith FILE *fd; 2762da392ccSBarry Smith int err; 2774a285bdaSBarry Smith 2784a285bdaSBarry Smith PetscFunctionBegin; 2799566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 280dd400576SPatrick Sanan if (rank == 0) { 2819566063dSJacob Faibussowitsch PetscCall(PetscStrcpy(head, "Authorization: Bearer ")); 2829566063dSJacob Faibussowitsch PetscCall(PetscStrcat(head, access_token)); 2839566063dSJacob Faibussowitsch PetscCall(PetscStrcat(head, "\r\n")); 2849566063dSJacob Faibussowitsch PetscCall(PetscStrcat(head, "uploadType: multipart\r\n")); 2854a285bdaSBarry Smith 2862da392ccSBarry Smith err = stat(filename, &sb); 28728b400f6SJacob Faibussowitsch PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to stat file: %s", filename); 2884a285bdaSBarry Smith len = 1024 + sb.st_size; 2899566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(len, &body)); 290d0609cedSBarry Smith PetscCall(PetscStrcpy(body, "--foo_bar_baz\r\n" 2914a285bdaSBarry Smith "Content-Type: application/json\r\n\r\n" 292d0609cedSBarry Smith "{")); 2939566063dSJacob Faibussowitsch PetscCall(PetscPushJSONValue(body, "title", filename, len)); 2949566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, ",")); 2959566063dSJacob Faibussowitsch PetscCall(PetscPushJSONValue(body, "mimeType", "text.html", len)); 2969566063dSJacob Faibussowitsch PetscCall(PetscStrcat(body, ",")); 2979566063dSJacob Faibussowitsch PetscCall(PetscPushJSONValue(body, "description", "a file", len)); 298d8174014SToby Isaac PetscCall(PetscStrcat(body, "}\r\n\r\n" 2994a285bdaSBarry Smith "--foo_bar_baz\r\n" 300d0609cedSBarry Smith "Content-Type: text/html\r\n\r\n")); 3019566063dSJacob Faibussowitsch PetscCall(PetscStrlen(body, &blen)); 3024a285bdaSBarry Smith fd = fopen(filename, "r"); 30328b400f6SJacob Faibussowitsch PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open file: %s", filename); 3044a285bdaSBarry Smith rd = fread(body + blen, sizeof(unsigned char), sb.st_size, fd); 305cc73adaaSBarry 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); 3064a285bdaSBarry Smith fclose(fd); 3074a285bdaSBarry Smith body[blen + rd] = 0; 308d0609cedSBarry Smith PetscCall(PetscStrcat(body, "\r\n\r\n" 309d0609cedSBarry Smith "--foo_bar_baz\r\n")); 3109566063dSJacob Faibussowitsch PetscCall(PetscSSLInitializeContext(&ctx)); 3119566063dSJacob Faibussowitsch PetscCall(PetscHTTPSConnect("www.boxapis.com", 443, ctx, &sock, &ssl)); 3129566063dSJacob Faibussowitsch PetscCall(PetscHTTPSRequest("POST", "www.boxapis.com/upload/drive/v2/files/", head, "multipart/related; boundary=\"foo_bar_baz\"", body, ssl, buff, sizeof(buff))); 3139566063dSJacob Faibussowitsch PetscCall(PetscFree(body)); 3149566063dSJacob Faibussowitsch PetscCall(PetscSSLDestroyContext(ctx)); 3154a285bdaSBarry Smith close(sock); 3169566063dSJacob Faibussowitsch PetscCall(PetscStrstr(buff, "\"title\"", &title)); 31728b400f6SJacob Faibussowitsch PetscCheck(title, PETSC_COMM_SELF, PETSC_ERR_LIB, "Upload of file %s failed", filename); 3184a285bdaSBarry Smith } 3194a285bdaSBarry Smith PetscFunctionReturn(0); 3204a285bdaSBarry Smith } 321