xref: /petsc/src/sys/webclient/box.c (revision 2b26979f2976cb8840d2aed9f03519841c1cab77)
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 
94a285bdaSBarry Smith    See -   http://stackoverflow.com/questions/4616553/using-oauth-in-free-open-source-software
104a285bdaSBarry Smith    Users can get their own application IDs - goto https://developers.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 
214a285bdaSBarry Smith static int PetscBoxWebServer_Private(struct mg_connection *conn)
224a285bdaSBarry Smith {
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 */
324a285bdaSBarry Smith static PetscErrorCode PetscBoxStartWebServer_Private(void)
334a285bdaSBarry Smith {
344a285bdaSBarry Smith   PetscErrorCode      ierr;
354a285bdaSBarry Smith   int                 optionsLen = 5;
364a285bdaSBarry Smith   const char          *options[optionsLen];
374a285bdaSBarry Smith   struct mg_callbacks callbacks;
384a285bdaSBarry Smith   struct mg_context   *ctx;
3968e69593SBarry Smith   char                keyfile[PETSC_MAX_PATH_LEN];
4068e69593SBarry Smith   PetscBool           exists;
414a285bdaSBarry Smith 
424a285bdaSBarry Smith   PetscFunctionBegin;
434a285bdaSBarry Smith   options[0] = "listening_ports";
444a285bdaSBarry Smith   options[1] = "8081s";
4568e69593SBarry Smith 
4668e69593SBarry Smith   ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr);
4768e69593SBarry Smith   ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr);
4868e69593SBarry Smith   if (!exists) {
4968e69593SBarry Smith     ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
5068e69593SBarry Smith     ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr);
5168e69593SBarry Smith     ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr);
5268e69593SBarry Smith     ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr);
5368e69593SBarry Smith     if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory");
5468e69593SBarry Smith   }
5568e69593SBarry Smith 
564a285bdaSBarry Smith   options[2] = "ssl_certificate";
5768e69593SBarry Smith   options[3] = keyfile;
584a285bdaSBarry Smith   options[4] = NULL;
594a285bdaSBarry Smith 
604a285bdaSBarry Smith   /* Prepare callbacks structure. We have only one callback, the rest are NULL. */
614a285bdaSBarry Smith   ierr = PetscMemzero(&callbacks, sizeof(callbacks));CHKERRQ(ierr);
624a285bdaSBarry Smith   callbacks.begin_request = PetscBoxWebServer_Private;
634a285bdaSBarry Smith   ctx = mg_start(&callbacks, NULL, options);
644a285bdaSBarry Smith   if (!ctx) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to start up webserver");
654a285bdaSBarry Smith   while (!result) {};
664a285bdaSBarry Smith   PetscFunctionReturn(0);
674a285bdaSBarry Smith }
684a285bdaSBarry Smith 
6968e69593SBarry Smith #if defined(PETSC_HAVE_UNISTD_H)
7068e69593SBarry Smith #include <unistd.h>
7168e69593SBarry Smith #endif
7268e69593SBarry Smith 
734a285bdaSBarry Smith #undef __FUNCT__
744a285bdaSBarry Smith #define __FUNCT__ "PetscBoxAuthorize"
754a285bdaSBarry Smith /*@C
764a285bdaSBarry Smith      PetscBoxAuthorize - Get authorization and refresh token for accessing Box drive from PETSc
774a285bdaSBarry Smith 
784a285bdaSBarry Smith    Not collective, only the first process in MPI_Comm does anything
794a285bdaSBarry Smith 
804a285bdaSBarry Smith    Input Parameters:
814a285bdaSBarry Smith +  comm - the MPI communicator
824a285bdaSBarry Smith -  tokensize - size of the token arrays
834a285bdaSBarry Smith 
844a285bdaSBarry Smith    Output Parameters:
854a285bdaSBarry Smith +  access_token - can be used with PetscBoxUpload() for this one session
864a285bdaSBarry Smith -  refresh_token - can be used for ever to obtain new access_tokens with PetscBoxRefresh(), guard this like a password
874a285bdaSBarry Smith                    it gives access to your Box Drive
884a285bdaSBarry Smith 
894a285bdaSBarry Smith    Notes: This call requires stdout and stdin access from process 0 on the MPI communicator
904a285bdaSBarry Smith 
91f044a08eSBarry Smith    You can run src/sys/webclient/examples/tutorials/boxobtainrefreshtoken to get a refresh token and then in the future pass it to
924a285bdaSBarry Smith    PETSc programs with -box_refresh_token XXX
934a285bdaSBarry Smith 
94f044a08eSBarry Smith    This requires PETSc be installed using --with-saws or --download-saws
95f044a08eSBarry Smith 
9668e69593SBarry Smith    Requires the user have created a self-signed ssl certificate with
9768e69593SBarry Smith 
9868e69593SBarry Smith $    saws/CA.pl  -newcert  (using the passphrase of password)
9968e69593SBarry Smith $    cat newkey.pem newcert.pem > sslclient.pem
10068e69593SBarry Smith 
10168e69593SBarry Smith     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
10268e69593SBarry Smith     silly but it was all I could figure out.
10368e69593SBarry Smith 
104*2b26979fSBarry Smith    Level: intermediate
105*2b26979fSBarry Smith 
1064a285bdaSBarry Smith .seealso: PetscBoxRefresh(), PetscBoxUpload(), PetscURLShorten()
1074a285bdaSBarry Smith 
1084a285bdaSBarry Smith @*/
1094a285bdaSBarry Smith PetscErrorCode PetscBoxAuthorize(MPI_Comm comm,char access_token[],char refresh_token[],size_t tokensize)
1104a285bdaSBarry Smith {
1114a285bdaSBarry Smith   SSL_CTX        *ctx;
1124a285bdaSBarry Smith   SSL            *ssl;
1134a285bdaSBarry Smith   int            sock;
1144a285bdaSBarry Smith   PetscErrorCode ierr;
1155dc0f0a4SBarry Smith   char           buff[8*1024],body[1024];
1164a285bdaSBarry Smith   PetscMPIInt    rank;
1175dc0f0a4SBarry Smith   PetscBool      flg,found;
1184a285bdaSBarry Smith 
1194a285bdaSBarry Smith   PetscFunctionBegin;
1204a285bdaSBarry Smith   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1214a285bdaSBarry Smith   if (!rank) {
12268e69593SBarry Smith     if (!isatty(fileno(PETSC_STDOUT))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Requires users input/output");
1234a285bdaSBarry Smith     ierr = PetscPrintf(comm,"Cut and paste the following into your browser:\n\n"
1244a285bdaSBarry Smith                             "https://www.box.com/api/oauth2/authorize?"
1254a285bdaSBarry Smith                             "response_type=code&"
1264a285bdaSBarry Smith                             "client_id="
1274a285bdaSBarry Smith                             PETSC_BOX_CLIENT_ID
1284a285bdaSBarry Smith                             "&state=PETScState"
1294a285bdaSBarry Smith                             "\n\n");CHKERRQ(ierr);
1304a285bdaSBarry Smith     ierr = PetscBoxStartWebServer_Private();CHKERRQ(ierr);
1314a285bdaSBarry Smith     ierr = PetscStrbeginswith((const char*)result,"state=PETScState&code=",&flg);CHKERRQ(ierr);
1324a285bdaSBarry Smith     if (!flg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not get expected string from Box got %s",result);
1334a285bdaSBarry Smith     ierr = PetscStrncpy(buff,(const char*)result+22,sizeof(buff));CHKERRQ(ierr);
1344a285bdaSBarry Smith 
1354a285bdaSBarry Smith     ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr);
1364a285bdaSBarry Smith     ierr = PetscHTTPSConnect("www.box.com",443,ctx,&sock,&ssl);CHKERRQ(ierr);
1374a285bdaSBarry Smith     ierr = PetscStrcpy(body,"code=");CHKERRQ(ierr);
1384a285bdaSBarry Smith     ierr = PetscStrcat(body,buff);CHKERRQ(ierr);
1394a285bdaSBarry Smith     ierr = PetscStrcat(body,"&client_id=");CHKERRQ(ierr);
1404a285bdaSBarry Smith     ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ID);CHKERRQ(ierr);
1414a285bdaSBarry Smith     ierr = PetscStrcat(body,"&client_secret=");CHKERRQ(ierr);
1424a285bdaSBarry Smith     ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ST);CHKERRQ(ierr);
1434a285bdaSBarry Smith     ierr = PetscStrcat(body,"&grant_type=authorization_code");CHKERRQ(ierr);
1444a285bdaSBarry Smith 
14593e1d32fSBarry Smith     ierr = PetscHTTPSRequest("POST","www.box.com/api/oauth2/token",NULL,"application/x-www-form-urlencoded",body,ssl,buff,sizeof(buff));CHKERRQ(ierr);
1464a285bdaSBarry Smith     ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr);
1474a285bdaSBarry Smith     close(sock);
1484a285bdaSBarry Smith 
1495dc0f0a4SBarry Smith     ierr   = PetscPullJSONValue(buff,"access_token",access_token,tokensize,&found);CHKERRQ(ierr);
1505dc0f0a4SBarry Smith     if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Box did not return access token");
1515dc0f0a4SBarry Smith     ierr   = PetscPullJSONValue(buff,"refresh_token",refresh_token,tokensize,&found);CHKERRQ(ierr);
1525dc0f0a4SBarry Smith     if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Box did not return refresh token");
1534a285bdaSBarry Smith 
1544a285bdaSBarry Smith     ierr = PetscPrintf(comm,"Here is your Box refresh token, save it in a save place, in the future you can run PETSc\n");CHKERRQ(ierr);
1555dc0f0a4SBarry Smith     ierr = PetscPrintf(comm,"programs with the option -box_refresh_token %s\n",refresh_token);CHKERRQ(ierr);
1564a285bdaSBarry Smith     ierr = PetscPrintf(comm,"to access Box Drive automatically\n");CHKERRQ(ierr);
1574a285bdaSBarry Smith   }
1584a285bdaSBarry Smith   PetscFunctionReturn(0);
1594a285bdaSBarry Smith }
160f044a08eSBarry Smith #endif
1614a285bdaSBarry Smith 
1624a285bdaSBarry Smith #undef __FUNCT__
1634a285bdaSBarry Smith #define __FUNCT__ "PetscBoxRefresh"
1644a285bdaSBarry Smith /*@C
1654a285bdaSBarry Smith      PetscBoxRefresh - Get a new authorization token for accessing Box drive from PETSc from a refresh token
1664a285bdaSBarry Smith 
1674a285bdaSBarry Smith    Not collective, only the first process in the MPI_Comm does anything
1684a285bdaSBarry Smith 
1694a285bdaSBarry Smith    Input Parameters:
1704a285bdaSBarry Smith +   comm - MPI communicator
1714a285bdaSBarry Smith .   refresh token - obtained with PetscBoxAuthorize(), if NULL PETSc will first look for one in the options data
1724a285bdaSBarry Smith                     if not found it will call PetscBoxAuthorize()
1734a285bdaSBarry Smith -   tokensize - size of the output string access_token
1744a285bdaSBarry Smith 
1754a285bdaSBarry Smith    Output Parameter:
1764a285bdaSBarry Smith +   access_token - token that can be passed to PetscBoxUpload()
1774a285bdaSBarry 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
1784a285bdaSBarry Smith 
179*2b26979fSBarry Smith    Level: intermediate
180*2b26979fSBarry Smith 
1814a285bdaSBarry Smith .seealso: PetscURLShorten(), PetscBoxAuthorize(), PetscBoxUpload()
1824a285bdaSBarry Smith 
1834a285bdaSBarry Smith @*/
1844a285bdaSBarry Smith PetscErrorCode PetscBoxRefresh(MPI_Comm comm,const char refresh_token[],char access_token[],char new_refresh_token[],size_t tokensize)
1854a285bdaSBarry Smith {
1864a285bdaSBarry Smith   SSL_CTX        *ctx;
1874a285bdaSBarry Smith   SSL            *ssl;
1884a285bdaSBarry Smith   int            sock;
1894a285bdaSBarry Smith   PetscErrorCode ierr;
1905dc0f0a4SBarry Smith   char           buff[8*1024],body[1024];
1914a285bdaSBarry Smith   PetscMPIInt    rank;
1925dc0f0a4SBarry Smith   char           *refreshtoken = (char*)refresh_token;
1935dc0f0a4SBarry Smith   PetscBool      found;
1944a285bdaSBarry Smith 
1954a285bdaSBarry Smith   PetscFunctionBegin;
1964a285bdaSBarry Smith   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1974a285bdaSBarry Smith   if (!rank) {
1984a285bdaSBarry Smith     if (!refresh_token) {
1994a285bdaSBarry Smith       PetscBool set;
2004a285bdaSBarry Smith       ierr = PetscMalloc1(512,&refreshtoken);CHKERRQ(ierr);
2014a285bdaSBarry Smith       ierr = PetscOptionsGetString(NULL,"-box_refresh_token",refreshtoken,512,&set);CHKERRQ(ierr);
20299374591SBarry Smith #if defined(PETSC_HAVE_SAWS)
2034a285bdaSBarry Smith       if (!set) {
20499374591SBarry Smith         ierr = PetscBoxAuthorize(comm,access_token,new_refresh_token,512*sizeof(char));CHKERRQ(ierr);
2054a285bdaSBarry Smith         ierr = PetscFree(refreshtoken);CHKERRQ(ierr);
2064a285bdaSBarry Smith         PetscFunctionReturn(0);
2074a285bdaSBarry Smith       }
20899374591SBarry Smith #else
20999374591SBarry Smith       if (!set) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Must provide refresh token with -box_refresh_token XXX");
21099374591SBarry Smith #endif
2114a285bdaSBarry Smith     }
2124a285bdaSBarry Smith     ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr);
2134a285bdaSBarry Smith     ierr = PetscHTTPSConnect("www.box.com",443,ctx,&sock,&ssl);CHKERRQ(ierr);
2144a285bdaSBarry Smith     ierr = PetscStrcpy(body,"client_id=");CHKERRQ(ierr);
2154a285bdaSBarry Smith     ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ID);CHKERRQ(ierr);
2164a285bdaSBarry Smith     ierr = PetscStrcat(body,"&client_secret=");CHKERRQ(ierr);
2174a285bdaSBarry Smith     ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ST);CHKERRQ(ierr);
2184a285bdaSBarry Smith     ierr = PetscStrcat(body,"&refresh_token=");CHKERRQ(ierr);
2194a285bdaSBarry Smith     ierr = PetscStrcat(body,refreshtoken);CHKERRQ(ierr);
2204a285bdaSBarry Smith     if (!refresh_token) {ierr = PetscFree(refreshtoken);CHKERRQ(ierr);}
2214a285bdaSBarry Smith     ierr = PetscStrcat(body,"&grant_type=refresh_token");CHKERRQ(ierr);
2224a285bdaSBarry Smith 
22393e1d32fSBarry Smith     ierr = PetscHTTPSRequest("POST","www.box.com/api/oauth2/token",NULL,"application/x-www-form-urlencoded",body,ssl,buff,sizeof(buff));CHKERRQ(ierr);
2244a285bdaSBarry Smith     ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr);
2254a285bdaSBarry Smith     close(sock);
2264a285bdaSBarry Smith 
2275dc0f0a4SBarry Smith     ierr   = PetscPullJSONValue(buff,"access_token",access_token,tokensize,&found);CHKERRQ(ierr);
2285dc0f0a4SBarry Smith     if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Box did not return access token");
2295dc0f0a4SBarry Smith     ierr   = PetscPullJSONValue(buff,"refresh_token",new_refresh_token,tokensize,&found);CHKERRQ(ierr);
2305dc0f0a4SBarry Smith     if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Box did not return refresh token");
23193e1d32fSBarry Smith 
23293e1d32fSBarry Smith     ierr = PetscPrintf(comm,"Here is your new Box refresh token, save it in a save place, in the future you can run PETSc\n");CHKERRQ(ierr);
2335dc0f0a4SBarry Smith     ierr = PetscPrintf(comm,"programs with the option -box_refresh_token %s\n",new_refresh_token);CHKERRQ(ierr);
23493e1d32fSBarry Smith     ierr = PetscPrintf(comm,"to access Box Drive automatically\n");CHKERRQ(ierr);
2354a285bdaSBarry Smith   }
2364a285bdaSBarry Smith   PetscFunctionReturn(0);
2374a285bdaSBarry Smith }
2384a285bdaSBarry Smith 
2394a285bdaSBarry Smith #include <sys/stat.h>
2404a285bdaSBarry Smith 
2414a285bdaSBarry Smith #undef __FUNCT__
2424a285bdaSBarry Smith #define __FUNCT__ "PetscBoxUpload"
2434a285bdaSBarry Smith /*@C
2444a285bdaSBarry Smith      PetscBoxUpload - Loads a file to the Box Drive
2454a285bdaSBarry Smith 
24693e1d32fSBarry Smith      This routine has not yet been written; it is just copied from Google Drive
24793e1d32fSBarry Smith 
2484a285bdaSBarry Smith      Not collective, only the first process in the MPI_Comm uploads the file
2494a285bdaSBarry Smith 
2504a285bdaSBarry Smith   Input Parameters:
2514a285bdaSBarry Smith +   comm - MPI communicator
2524a285bdaSBarry Smith .   access_token - obtained with PetscBoxRefresh(), pass NULL to have PETSc generate one
2534a285bdaSBarry Smith -   filename - file to upload; if you upload multiple times it will have different names each time on Box Drive
2544a285bdaSBarry Smith 
2554a285bdaSBarry Smith   Options Database:
2564a285bdaSBarry Smith .  -box_refresh_token   XXX
2574a285bdaSBarry Smith 
2584a285bdaSBarry Smith   Usage Patterns:
2594a285bdaSBarry Smith     With PETSc option -box_refresh_token  XXX given
2604a285bdaSBarry Smith     PetscBoxUpload(comm,NULL,filename);        will upload file with no user interaction
2614a285bdaSBarry Smith 
2624a285bdaSBarry Smith     Without PETSc option -box_refresh_token XXX given
2634a285bdaSBarry Smith     PetscBoxUpload(comm,NULL,filename);        for first use will prompt user to authorize access to Box Drive with their processor
2644a285bdaSBarry Smith 
2654a285bdaSBarry Smith     With PETSc option -box_refresh_token  XXX given
2664a285bdaSBarry Smith     PetscBoxRefresh(comm,NULL,access_token,sizeof(access_token));
2674a285bdaSBarry Smith     PetscBoxUpload(comm,access_token,filename);
2684a285bdaSBarry Smith 
2694a285bdaSBarry Smith     With refresh token entered in some way by the user
2704a285bdaSBarry Smith     PetscBoxRefresh(comm,refresh_token,access_token,sizeof(access_token));
2714a285bdaSBarry Smith     PetscBoxUpload(comm,access_token,filename);
2724a285bdaSBarry Smith 
2734a285bdaSBarry Smith     PetscBoxAuthorize(comm,access_token,refresh_token,sizeof(access_token));
2744a285bdaSBarry Smith     PetscBoxUpload(comm,access_token,filename);
2754a285bdaSBarry Smith 
276*2b26979fSBarry Smith    Level: intermediate
277*2b26979fSBarry Smith 
2784a285bdaSBarry Smith .seealso: PetscURLShorten(), PetscBoxAuthorize(), PetscBoxRefresh()
2794a285bdaSBarry Smith 
2804a285bdaSBarry Smith @*/
2814a285bdaSBarry Smith PetscErrorCode PetscBoxUpload(MPI_Comm comm,const char access_token[],const char filename[])
2824a285bdaSBarry Smith {
2834a285bdaSBarry Smith   SSL_CTX        *ctx;
2844a285bdaSBarry Smith   SSL            *ssl;
2854a285bdaSBarry Smith   int            sock;
2864a285bdaSBarry Smith   PetscErrorCode ierr;
2874a285bdaSBarry Smith   char           head[1024],buff[8*1024],*body,*title;
2884a285bdaSBarry Smith   PetscMPIInt    rank;
2894a285bdaSBarry Smith   struct stat    sb;
2904a285bdaSBarry Smith   size_t         len,blen,rd;
2914a285bdaSBarry Smith   FILE           *fd;
2924a285bdaSBarry Smith 
2934a285bdaSBarry Smith   PetscFunctionBegin;
2944a285bdaSBarry Smith   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
2954a285bdaSBarry Smith   if (!rank) {
2964a285bdaSBarry Smith     ierr = PetscStrcpy(head,"Authorization: Bearer ");CHKERRQ(ierr);
2974a285bdaSBarry Smith     ierr = PetscStrcat(head,access_token);CHKERRQ(ierr);
2984a285bdaSBarry Smith     ierr = PetscStrcat(head,"\r\n");CHKERRQ(ierr);
2994a285bdaSBarry Smith     ierr = PetscStrcat(head,"uploadType: multipart\r\n");CHKERRQ(ierr);
3004a285bdaSBarry Smith 
3014a285bdaSBarry Smith     ierr = stat(filename,&sb);
3024a285bdaSBarry Smith     if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to stat file: %s",filename);
3034a285bdaSBarry Smith     len = 1024 + sb.st_size;
3044a285bdaSBarry Smith     ierr = PetscMalloc1(len,&body);CHKERRQ(ierr);
3054a285bdaSBarry Smith     ierr = PetscStrcpy(body,"--foo_bar_baz\r\n"
3064a285bdaSBarry Smith                             "Content-Type: application/json\r\n\r\n"
3075dc0f0a4SBarry Smith                             "{");CHKERRQ(ierr);
3085dc0f0a4SBarry Smith     ierr = PetscPushJSONValue(body,"title",filename,len);CHKERRQ(ierr);
3095dc0f0a4SBarry Smith     ierr = PetscStrcat(body,",");CHKERRQ(ierr);
3105dc0f0a4SBarry Smith     ierr = PetscPushJSONValue(body,"mimeType","text.html",len);CHKERRQ(ierr);
3115dc0f0a4SBarry Smith     ierr = PetscStrcat(body,",");CHKERRQ(ierr);
3125dc0f0a4SBarry Smith     ierr = PetscPushJSONValue(body,"description","a file",len);CHKERRQ(ierr);
3135dc0f0a4SBarry Smith     ierr = PetscStrcat(body, "}\r\n\r\n"
3144a285bdaSBarry Smith                              "--foo_bar_baz\r\n"
3155dc0f0a4SBarry Smith                              "Content-Type: text/html\r\n\r\n");CHKERRQ(ierr);
3164a285bdaSBarry Smith     ierr = PetscStrlen(body,&blen);CHKERRQ(ierr);
3174a285bdaSBarry Smith     fd = fopen (filename, "r");
3184a285bdaSBarry Smith     if (!fd) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open file: %s",filename);
3194a285bdaSBarry Smith     rd = fread (body+blen, sizeof (unsigned char), sb.st_size, fd);
3207a3410edSBarry Smith     if (rd != (size_t)sb.st_size) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to read entire file: %s %d %d",filename,(int)rd,(int)sb.st_size);
3214a285bdaSBarry Smith     fclose(fd);
3224a285bdaSBarry Smith     body[blen + rd] = 0;
3234a285bdaSBarry Smith     ierr = PetscStrcat(body,"\r\n\r\n"
3244a285bdaSBarry Smith                             "--foo_bar_baz\r\n");
3254a285bdaSBarry Smith     ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr);
3264a285bdaSBarry Smith     ierr = PetscHTTPSConnect("www.boxapis.com",443,ctx,&sock,&ssl);CHKERRQ(ierr);
32793e1d32fSBarry Smith     ierr = PetscHTTPSRequest("POST","www.boxapis.com/upload/drive/v2/files/",head,"multipart/related; boundary=\"foo_bar_baz\"",body,ssl,buff,sizeof(buff));CHKERRQ(ierr);
3284a285bdaSBarry Smith     ierr = PetscFree(body);CHKERRQ(ierr);
3294a285bdaSBarry Smith     ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr);
3304a285bdaSBarry Smith     close(sock);
3314a285bdaSBarry Smith     ierr   = PetscStrstr(buff,"\"title\"",&title);CHKERRQ(ierr);
3324a285bdaSBarry Smith     if (!title) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Upload of file %s failed",filename);
3334a285bdaSBarry Smith   }
3344a285bdaSBarry Smith   PetscFunctionReturn(0);
3354a285bdaSBarry Smith }
3364a285bdaSBarry Smith 
3374a285bdaSBarry Smith 
338